Upload 10 files
Browse files- .gitignore +5 -0
- download_audio.py +69 -0
- gemini_normalize.py +53 -0
- gen_dataset.py +19 -0
- main.py +136 -0
- separate.py +108 -0
- test_dataset.py +90 -0
- text_nomalize.py +128 -0
- upload_huggingface.py +16 -0
.gitignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.env
|
2 |
+
downloaded_audio/
|
3 |
+
figures/
|
4 |
+
audio_cut/
|
5 |
+
audio_cut.zip
|
download_audio.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import yt_dlp
|
2 |
+
import os
|
3 |
+
import subprocess
|
4 |
+
import shutil
|
5 |
+
from pydub import AudioSegment
|
6 |
+
from pydub.playback import play
|
7 |
+
import os
|
8 |
+
import tempfile
|
9 |
+
from pytube import Playlist
|
10 |
+
def download_and_convert_audio(url, path,idx, sample_rate=24000):
|
11 |
+
ydl_opts = {
|
12 |
+
'format': 'bestaudio/best',
|
13 |
+
'postprocessors': [{
|
14 |
+
'key': 'FFmpegExtractAudio',
|
15 |
+
'preferredcodec': 'wav',
|
16 |
+
}],
|
17 |
+
'outtmpl': '%(title)s.%(ext)s',
|
18 |
+
}
|
19 |
+
|
20 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
21 |
+
info = ydl.extract_info(url, download=True)
|
22 |
+
filename = ydl.prepare_filename(info)
|
23 |
+
original_filename = os.path.splitext(filename)[0] + '.wav'
|
24 |
+
print("original_filename",original_filename)
|
25 |
+
|
26 |
+
|
27 |
+
# Convert sample rate using FFmpeg
|
28 |
+
# temp_filename = output_filename.split("/")[0]+ 'temp_' + output_filename.split("/")[1]
|
29 |
+
direc = path + original_filename[:30] +"_"
|
30 |
+
if not os.path.exists(direc):
|
31 |
+
os.makedirs(direc)
|
32 |
+
|
33 |
+
output_filename = direc + "/" +str(idx) + ".wav"
|
34 |
+
subprocess.run([
|
35 |
+
'ffmpeg', '-i', original_filename,
|
36 |
+
'-ar', str(sample_rate),
|
37 |
+
output_filename
|
38 |
+
])
|
39 |
+
|
40 |
+
|
41 |
+
os.remove(original_filename)
|
42 |
+
print(f"Audio downloaded and converted: {output_filename}")
|
43 |
+
return output_filename
|
44 |
+
|
45 |
+
from pydub import AudioSegment
|
46 |
+
|
47 |
+
def cut_audio(root):
|
48 |
+
total_duration = 0
|
49 |
+
for folder in os.listdir(root):
|
50 |
+
path = root + folder + '/'
|
51 |
+
file = os.listdir(path)[0]
|
52 |
+
audio = AudioSegment.from_wav(path + file)
|
53 |
+
audio = audio[30 * 1000: 6 * 60 * 1000 + 30 * 1000 ]
|
54 |
+
save_path = "audio_cut/" +file
|
55 |
+
audio.export(save_path, format="wav")
|
56 |
+
total_duration += len(audio)
|
57 |
+
if total_duration > 7*60*60*1000:
|
58 |
+
break
|
59 |
+
|
60 |
+
|
61 |
+
if __name__ == '__main__':
|
62 |
+
playlist_url = 'https://www.youtube.com/playlist?list=PLd7oGuDX6k1CD0EaggVT3kV6MjGqbVV9k'
|
63 |
+
|
64 |
+
# Thư mục lưu trữ file âm thanh tải về
|
65 |
+
save_path = 'audio_cut/'
|
66 |
+
|
67 |
+
# Tạo thư mục nếu chưa tồn tại
|
68 |
+
cut_audio("downloaded_audio/")
|
69 |
+
|
gemini_normalize.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Install the Google AI Python SDK
|
3 |
+
|
4 |
+
$ pip install google-generativeai
|
5 |
+
"""
|
6 |
+
|
7 |
+
import os
|
8 |
+
import google.generativeai as genai
|
9 |
+
|
10 |
+
from dotenv import load_dotenv
|
11 |
+
load_dotenv()
|
12 |
+
api_key = os.getenv('GEMINI_API_KEY')
|
13 |
+
|
14 |
+
genai.configure(api_key=api_key)
|
15 |
+
|
16 |
+
# Create the model
|
17 |
+
generation_config = {
|
18 |
+
"temperature": 0,
|
19 |
+
"top_p": 0.95,
|
20 |
+
"top_k": 64,
|
21 |
+
"max_output_tokens": 8192,
|
22 |
+
"response_mime_type": "text/plain",
|
23 |
+
}
|
24 |
+
|
25 |
+
model = genai.GenerativeModel(
|
26 |
+
model_name="gemini-1.5-pro-exp-0827",
|
27 |
+
generation_config=generation_config,
|
28 |
+
# safety_settings = Adjust safety settings
|
29 |
+
# See https://ai.google.dev/gemini-api/docs/safety-settings
|
30 |
+
)
|
31 |
+
|
32 |
+
|
33 |
+
def call_api(text):
|
34 |
+
chat_session = model.start_chat(
|
35 |
+
history=[
|
36 |
+
{
|
37 |
+
"role": "user",
|
38 |
+
"parts": [
|
39 |
+
"# Prompt:\n\"You are an expert in Vietnamese language normalization, specializing in transforming informal, professional, and complex text into clear, well-structured Vietnamese. Your task is to normalize a list of Vietnamese sentences to ensure they are grammatically correct, accurately convey the intended meaning, and are consistent with the writing conventions of formal Vietnamese.\n\n# Rules:\nI will give you a list of sentences to normalize.\nYour task is to transform the sentences into their most formal and correct form while maintaining the original meaning. This includes handling numbers, dates, measurements, abbreviations, names, and any polysemic words appropriately.\nEnsure that numbers (including decimals, fractions), time, currency, and units are expressed in full written form.\nIf there are informal expressions, rewrite them into formal, clear language.\nMaintain proper noun names, abbreviations, or technical terms as is when necessary.\nAbsolutely do not change the original content or remove any part of the text.\nDo not add any new words unless they are necessary for the process of normalization. Only add words if they are essential for formalizing or clarifying the original text (e.g., converting abbreviations or numeric forms into written language).\nFor words that have become commonly used in Vietnamese, such as \"nét\" (referring to \"internet\"), keep them as they are in the original text. Do not attempt to translate these words into their English equivalents. Focus on maintaining the natural usage of these words in the context of the sentence.\nFor all instances where numbers are used (e.g., U17, COVID-19, F12,G9), convert the numbers to their full written form in Vietnamese. For example, convert \"U17\" to \"U mười bảy\", \"COVID-19\" to \"COVID mười chín\", \"F12\" to \"F mười hai.\", \"G9\" to \"G chín\".\nFor sentences that do not require any normalization, keep them exactly as they are. Do not make any changes to such sentences.\nAvoid unnecessary rephrasing unless absolutely required to maintain clarity and fluency.\nReply with the normalized sentences only, without any explanation.\nIf a sentence is very complex or informal, aim to restructure it for maximum clarity and readability.\nAlways prioritize accuracy and fluency in your normalization.\"\n# Example\n- Input1:\n[\n \"TS Nguyễn Văn A mua 5kg gạo với giá 12.500 VND/kg từ 8h30 đến 10h30 ngày 12/03/2023. SĐT: 0909 123 456.\",\n \"Chị H thuê 3 căn hộ, mỗi căn rộng 120m2 với giá 8.000.000 VND/tháng từ tháng 01 đến tháng 03.\",\n \"V. là giai đoạn 2/3 của dự án với chi phí 1.500.000 VND và thời gian thực hiện từ 09:00 đến 17:00.\"\n]\n\n- Output1:\n[\n \"Tiến sĩ Nguyễn Văn A mua năm kilogram gạo với giá mười hai nghìn năm trăm đồng một kilogram từ tám giờ ba mươi phút đến mười giờ ba mươi phút ngày mười hai tháng ba năm hai nghìn không trăm hai mươi ba. Số điện thoại: không chín không chín một hai ba bốn năm sáu.\",\n \"Chị H thuê ba căn hộ, mỗi căn rộng một trăm hai mươi mét vuông với giá tám triệu đồng một tháng từ tháng một đến tháng ba.\",\n \"Năm là giai đoạn hai phần ba của dự án với chi phí một triệu năm trăm nghìn đồng và thời gian thực hiện từ chín giờ đến mười bảy giờ.\"\n]\n- Input 2:\n[\n \"Anh T dùng 1/4 giờ để chạy quãng đường 5km với vận tốc 20,25 km/h. Chi phí là 100.000 VND.\",\n \"Cô B đã hoàn thành cuộc thi trong 1/3 thời gian dự kiến và giành vị trí thứ 2. ROMAN III là đối thủ xếp sau.\",\n \"Số tiền 2.000.000 VND đã được gửi vào tài khoản lúc 15:45.\"\n]\n- Output2:\n[\n \"Anh T dùng một phần tư giờ để chạy quãng đường năm kilomet với vận tốc hai mươi phẩy hai lăm kilomet một giờ. Chi phí là một trăm nghìn đồng.\",\n \"Cô B đã hoàn thành cuộc thi trong một phần ba thời gian dự kiến và giành vị trí thứ hai. Ba theo La Mã là đối thủ xếp sau.\",\n \"Số tiền hai triệu đồng đã đ��ợc gửi vào tài khoản lúc mười lăm giờ bốn mươi lăm phút.\"\n]\n- Input3:\n[\n\"Anh ấy dành 2 tiếng để lướt nét mỗi ngày.\",\n\"Cô ấy thường xuyên đăng ảnh lên phây.\",\n\"Họ gu gồ thông tin về chuyến du lịch sắp tới.\"\n]\n- Output3:\n[\n\"Anh ấy dành hai tiếng để lướt nét mỗi ngày.\",\n\"Cô ấy thường xuyên đăng ảnh lên phây.\",\n\"Họ gu gồ thông tin về chuyến du lịch sắp tới.\"\n]\n- Input 4 :\n[\"với những thông tin trên mà tài chính kinh doanh chia sẻ, hy vọng các bạn sinh viên sẽ tìm được một công việc phù hợp để kiếm thêm thu nhập nhé.\"]\n- Output 4:\n[\"với những thông tin trên mà tài chính kinh doanh chia sẻ, hy vọng các bạn sinh viên sẽ tìm được một công việc phù hợp để kiếm thêm thu nhập nhé.\"]\n- Input 5 :\n[\"Tuy nhiên, bạn cần chú ý đến mặt cạnh tranh và khả năng quảng cáo, marketing đặc biệt để tối ưu hóa khả năng kinh doanh.\",\"đầu tiên, bạn có thể xây dựng chuồng trại, nuôi các loại da súc, da cầm, sau đó có thể tận dụng chất thải từ chăn nuôi làm phân bón cho các loại cây.\" , \"Tuy nhiên, nếu mua con giống sinh sản, thiết nghĩ quý vị và các bạn nên chọn vùng đất dễ xây dựng chuồng vì giống dê này nhân đàn rất nhanh.\"]\n- Output 5 :\n[\"Tuy nhiên, bạn cần chú ý đến mặt cạnh tranh và khả năng quảng cáo, marketing đặc biệt để tối ưu hóa khả năng kinh doanh.\",\"đầu tiên, bạn có thể xây dựng chuồng trại, nuôi các loại da súc, da cầm, sau đó có thể tận dụng chất thải từ chăn nuôi làm phân bón cho các loại cây.\" , \"Tuy nhiên, nếu mua con giống sinh sản, thiết nghĩ quý vị và các bạn nên chọn vùng đất dễ xây dựng chuồng vì giống dê này nhân đàn rất nhanh.\"]\n- input 6 :\n[\"Trong khu chuồng nuôi, bà con cần chia thành ô chuồng nhỏ với diện tích từ 10 đến 20 m2, thường là vách ngăn được xây bằng gạch hoặc cắt thành gỗ kép lại.\"]\n- output 6 :\n[\"Trong khu chuồng nuôi, bà con cần chia thành ô chuồng nhỏ với diện tích từ mười đến hai mươi mét vuông, thường là vách ngăn được xây bằng gạch hoặc cắt thành gỗ kép lại.\"]\n- input 7 : \n['Nguyên Phong, Ninh Thuận, U17 Khánh Hòa, Star Kids, hay các trang truyền lửa cho bóng đá trên mạng xã hội.','Trên cánh đồng ngô nếp ở thôn 1, xã Tường Sơn, ngay từ sáng sớm người dân đã nhộn nhịp ra đồng thu hoạch để bán cho thương lái.', 'Tuy nhiên, trong giai đoạn dịch COVID-19 bùng phát, câu chuyện kêu gọi giải cứu thanh long đỏ gây sốt giới truyền thông cả trong và ngoài nước.',\"top 4 người tôi luôn tin tưởng nhất\"]\n- output 7 :\n['Nguyên Phong, Ninh Thuận, U mười bảy Khánh Hòa, Star Kids, hay các trang truyền lửa cho bóng đá trên mạng xã hội.', Trên cánh đồng ngô nếp ở thôn một, xã Tường Sơn, ngay từ sáng sớm người dân đã nhộn nhịp ra đồng thu hoạch để bán cho thương lái.','Tuy nhiên, trong giai đoạn dịch COVID mười chín bùng phát, câu chuyện kêu gọi giải cứu thanh long đỏ gây sốt giới truyền thông cả trong và ngoài nước.',\"top bốn người tôi luôn tin tưởng nhất\"]\n",
|
40 |
+
],
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"role": "model",
|
44 |
+
"parts": [
|
45 |
+
"- Output 7 :\n['Nguyên Phong, Ninh Thuận, U mười bảy Khánh Hòa, Star Kids, hay các trang truyền lửa cho bóng đá trên mạng xã hội.', 'Trên cánh đồng ngô nếp ở thôn một, xã Tường Sơn, ngay từ sáng sớm người dân đã nhộn nhịp ra đồng thu hoạch để bán cho thương lái.', 'Tuy nhiên, trong giai đoạn dịch COVID mười chín bùng phát, câu chuyện kêu gọi giải cứu thanh long đỏ gây sốt giới truyền thông cả trong và ngoài nước.', 'top bốn người tôi luôn tin tưởng nhất']",
|
46 |
+
],
|
47 |
+
},
|
48 |
+
]
|
49 |
+
)
|
50 |
+
|
51 |
+
response = chat_session.send_message(text)
|
52 |
+
print(response.text)
|
53 |
+
return eval(response.text)
|
gen_dataset.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import whisperx
|
2 |
+
|
3 |
+
audio_path = "audio_cut/4.wav"
|
4 |
+
device = "cuda"
|
5 |
+
batch_size = 4 # reduce if low on GPU mem
|
6 |
+
compute_type = "float32" # change to "int8" if low on GPU mem (may reduce accuracy)
|
7 |
+
|
8 |
+
# 1. Transcribe with original whisper (batched)
|
9 |
+
model_dir = "figures/"
|
10 |
+
model = whisperx.load_model("medium", device, compute_type=compute_type, download_root=model_dir,language="vi")
|
11 |
+
audio = whisperx.load_audio(audio_path)
|
12 |
+
result = model.transcribe(audio, batch_size=batch_size,chunk_size=10
|
13 |
+
)
|
14 |
+
print(result)
|
15 |
+
|
16 |
+
import json
|
17 |
+
|
18 |
+
# with open('data.json', 'w', encoding='utf-8') as json_file:
|
19 |
+
# json.dump(data, json_file, ensure_ascii=False, indent=4)
|
main.py
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydub import AudioSegment
|
2 |
+
import pandas as pd
|
3 |
+
import nltk
|
4 |
+
from nltk.tokenize import TweetTokenizer
|
5 |
+
word_tokenize = TweetTokenizer().tokenize
|
6 |
+
from text_nomalize import normalize_single
|
7 |
+
|
8 |
+
from gemini_normalize import call_api
|
9 |
+
def replace_t(word):
|
10 |
+
x = "t̪"
|
11 |
+
return word.replace(x, 't0')
|
12 |
+
|
13 |
+
def replace_special_char(word):
|
14 |
+
special_chars_to_ignore = "̪̃/^"
|
15 |
+
for char in special_chars_to_ignore:
|
16 |
+
word= word.replace(char, '')
|
17 |
+
return word
|
18 |
+
def clean_word(input_string):
|
19 |
+
special_chars = "{<[)}>(]"
|
20 |
+
for char in special_chars:
|
21 |
+
input_string = input_string.replace(char, '"')
|
22 |
+
return input_string
|
23 |
+
|
24 |
+
import phonemizer
|
25 |
+
global_phonemizer = phonemizer.backend.EspeakBackend(language='vi', preserve_punctuation=True, with_stress=True,language_switch='remove-flags',words_mismatch='ignore')
|
26 |
+
def has_numbers(inputString):
|
27 |
+
return any(char.isdigit() for char in inputString)
|
28 |
+
|
29 |
+
def word_process(parquet_path):
|
30 |
+
df = pd.read_parquet(parquet_path, engine='fastparquet')
|
31 |
+
for index, row in df.iterrows():
|
32 |
+
text = df.loc[index, 'normal_text']
|
33 |
+
|
34 |
+
text = word_tokenize(text)
|
35 |
+
text = [clean_word(word) for word in text]
|
36 |
+
|
37 |
+
text = ' '.join(text)
|
38 |
+
|
39 |
+
ps = global_phonemizer.phonemize([text])
|
40 |
+
print(ps)
|
41 |
+
ps = [replace_t(p) for p in ps]
|
42 |
+
print(ps)
|
43 |
+
ps = [replace_special_char(p) for p in ps]
|
44 |
+
df.loc[index, 'phonemes'] = ps[0]
|
45 |
+
|
46 |
+
df.to_parquet(parquet_path, engine='fastparquet')
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
|
52 |
+
def generate(root_path,parquet_file):
|
53 |
+
total_duration = 0
|
54 |
+
|
55 |
+
df = pd.read_parquet(root_path+"/"+parquet_file, engine='fastparquet')
|
56 |
+
new_df = pd.DataFrame(columns=['audio.path', 'text','speaker_id'])
|
57 |
+
for index, row in df.iterrows():
|
58 |
+
|
59 |
+
file= df.loc[index, 'audio.path']
|
60 |
+
text = df.loc[index, 'text']
|
61 |
+
|
62 |
+
audio = AudioSegment.from_wav(file)
|
63 |
+
if len(audio)/1000.0>6 and len(audio)/1000.0<9:
|
64 |
+
total_duration += len(audio)
|
65 |
+
new_df = new_df.append({'audio.path':file,'text':text,'speaker_id':0},ignore_index=True)
|
66 |
+
|
67 |
+
|
68 |
+
if total_duration/(1000*60*60)>=1:
|
69 |
+
print(new_df.head())
|
70 |
+
new_df =new_df.reset_index(drop=True)
|
71 |
+
new_df.to_parquet(root_path+"/"+"Xanh24h_1h.parquet", engine='fastparquet')
|
72 |
+
break
|
73 |
+
|
74 |
+
def normalize_text(parquet_file):
|
75 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
76 |
+
req = []
|
77 |
+
print(df.shape[0]-1)
|
78 |
+
dem = 0
|
79 |
+
for index, row in df.iterrows():
|
80 |
+
text = df.loc[index, 'text']
|
81 |
+
req.append(text)
|
82 |
+
# print(index)
|
83 |
+
if len(req)==50 or index == df.shape[0]-1:
|
84 |
+
res = call_api(str(req))
|
85 |
+
|
86 |
+
for idx,r in enumerate(res):
|
87 |
+
df.loc[50*dem+idx, 'normal_text'] = r
|
88 |
+
dem+=1
|
89 |
+
req = []
|
90 |
+
for index, row in df.iterrows():
|
91 |
+
if has_numbers(df.loc[index, 'normal_text']):
|
92 |
+
print("has number",df.loc[index, 'normal_text'])
|
93 |
+
elif df.loc[index, 'normal_text'] != df.loc[index, 'text'] and not has_numbers(df.loc[index, 'text']):
|
94 |
+
print(df.loc[index, 'normal_text'])
|
95 |
+
print(df.loc[index, 'text'])
|
96 |
+
|
97 |
+
df.to_parquet(parquet_file, engine='fastparquet')
|
98 |
+
|
99 |
+
|
100 |
+
def read(parquet_file):
|
101 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
102 |
+
for index, row in df.iterrows():
|
103 |
+
if has_numbers(df.loc[index, 'normal_text']):
|
104 |
+
print("has number",df.loc[index, 'normal_text'])
|
105 |
+
elif df.loc[index, 'normal_text'] != df.loc[index, 'text'] and not has_numbers(df.loc[index, 'text']):
|
106 |
+
print(df.loc[index, 'normal_text'])
|
107 |
+
print(df.loc[index, 'text'])
|
108 |
+
print(df.loc[index, 'audio.path'])
|
109 |
+
df.loc[index, 'normal_text'] =df.loc[index, 'text']
|
110 |
+
# df.to_parquet(parquet_file, engine='fastparquet')
|
111 |
+
|
112 |
+
def copy_audio(parquet_file):
|
113 |
+
import shutil
|
114 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
115 |
+
for index, row in df.iterrows():
|
116 |
+
file= df.loc[index, 'audio.path']
|
117 |
+
shutil.copy2(file, file.replace("dataset","data"))
|
118 |
+
|
119 |
+
def export(parquet_file,output_file):
|
120 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
121 |
+
data =[]
|
122 |
+
for index, row in df.iterrows():
|
123 |
+
data.append(f"{df.loc[index, 'audio.path']}|{df.loc[index, 'phonemes']}|0")
|
124 |
+
|
125 |
+
with open(output_file, 'w',encoding="utf-8") as f:
|
126 |
+
for item in data:
|
127 |
+
f.write("%s\n" % item)
|
128 |
+
|
129 |
+
|
130 |
+
if __name__ == "__main__":
|
131 |
+
# generate("dataset","Xanh24h.parquet")
|
132 |
+
# normalize_text("dataset/Xanh24h_1h.parquet")
|
133 |
+
# read("dataset/Xanh24h_1h.parquet")
|
134 |
+
word_process("dataset/Xanh24h_1h_test.parquet")
|
135 |
+
# copy_audio("dataset/Xanh24h_1h.parquet")
|
136 |
+
export("dataset/Xanh24h_1h_test.parquet","val_list.txt")
|
separate.py
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os,sys,torch,warnings,pdb
|
2 |
+
warnings.filterwarnings("ignore")
|
3 |
+
import librosa
|
4 |
+
import importlib
|
5 |
+
import numpy as np
|
6 |
+
import hashlib , math
|
7 |
+
from tqdm import tqdm
|
8 |
+
from uvr5_pack.lib_v5 import spec_utils
|
9 |
+
from uvr5_pack.utils import _get_name_params,inference
|
10 |
+
from uvr5_pack.lib_v5.model_param_init import ModelParameters
|
11 |
+
from scipy.io import wavfile
|
12 |
+
|
13 |
+
class _audio_pre_():
|
14 |
+
def __init__(self, model_path,device,is_half):
|
15 |
+
self.model_path = model_path
|
16 |
+
self.device = device
|
17 |
+
self.data = {
|
18 |
+
# Processing Options
|
19 |
+
'postprocess': False,
|
20 |
+
'tta': False,
|
21 |
+
# Constants
|
22 |
+
'window_size': 512,
|
23 |
+
'agg': 10,
|
24 |
+
'high_end_process': 'mirroring',
|
25 |
+
}
|
26 |
+
nn_arch_sizes = [
|
27 |
+
31191, # default
|
28 |
+
33966,61968, 123821, 123812, 537238 # custom
|
29 |
+
]
|
30 |
+
self.nn_architecture = list('{}KB'.format(s) for s in nn_arch_sizes)
|
31 |
+
model_size = math.ceil(os.stat(model_path ).st_size / 1024)
|
32 |
+
nn_architecture = '{}KB'.format(min(nn_arch_sizes, key=lambda x:abs(x-model_size)))
|
33 |
+
nets = importlib.import_module('uvr5_pack.lib_v5.nets' + f'_{nn_architecture}'.replace('_{}KB'.format(nn_arch_sizes[0]), ''), package=None)
|
34 |
+
model_hash = hashlib.md5(open(model_path,'rb').read()).hexdigest()
|
35 |
+
param_name ,model_params_d = _get_name_params(model_path , model_hash)
|
36 |
+
|
37 |
+
mp = ModelParameters(model_params_d)
|
38 |
+
model = nets.CascadedASPPNet(mp.param['bins'] * 2)
|
39 |
+
cpk = torch.load( model_path , map_location='cpu')
|
40 |
+
model.load_state_dict(cpk)
|
41 |
+
model.eval()
|
42 |
+
if(is_half==True):model = model.half().to(device)
|
43 |
+
else:model = model.to(device)
|
44 |
+
|
45 |
+
self.mp = mp
|
46 |
+
self.model = model
|
47 |
+
|
48 |
+
def _path_audio_(self, music_file ,ins_root=None,vocal_root=None):
|
49 |
+
if(ins_root is None and vocal_root is None):return "No save root."
|
50 |
+
name=os.path.basename(music_file)
|
51 |
+
if(ins_root is not None):os.makedirs(ins_root, exist_ok=True)
|
52 |
+
if(vocal_root is not None):os.makedirs(vocal_root , exist_ok=True)
|
53 |
+
X_wave, y_wave, X_spec_s, y_spec_s = {}, {}, {}, {}
|
54 |
+
bands_n = len(self.mp.param['band'])
|
55 |
+
# print(bands_n)
|
56 |
+
for d in range(bands_n, 0, -1):
|
57 |
+
bp = self.mp.param['band'][d]
|
58 |
+
if d == bands_n: # high-end band
|
59 |
+
X_wave[d], _ = librosa.core.load(
|
60 |
+
music_file, bp['sr'], False, dtype=np.float32, res_type=bp['res_type'])
|
61 |
+
if X_wave[d].ndim == 1:
|
62 |
+
X_wave[d] = np.asfortranarray([X_wave[d], X_wave[d]])
|
63 |
+
else: # lower bands
|
64 |
+
X_wave[d] = librosa.core.resample(X_wave[d+1], self.mp.param['band'][d+1]['sr'], bp['sr'], res_type=bp['res_type'])
|
65 |
+
# Stft of wave source
|
66 |
+
X_spec_s[d] = spec_utils.wave_to_spectrogram_mt(X_wave[d], bp['hl'], bp['n_fft'], self.mp.param['mid_side'], self.mp.param['mid_side_b2'], self.mp.param['reverse'])
|
67 |
+
# pdb.set_trace()
|
68 |
+
if d == bands_n and self.data['high_end_process'] != 'none':
|
69 |
+
input_high_end_h = (bp['n_fft']//2 - bp['crop_stop']) + ( self.mp.param['pre_filter_stop'] - self.mp.param['pre_filter_start'])
|
70 |
+
input_high_end = X_spec_s[d][:, bp['n_fft']//2-input_high_end_h:bp['n_fft']//2, :]
|
71 |
+
|
72 |
+
X_spec_m = spec_utils.combine_spectrograms(X_spec_s, self.mp)
|
73 |
+
aggresive_set = float(self.data['agg']/100)
|
74 |
+
aggressiveness = {'value': aggresive_set, 'split_bin': self.mp.param['band'][1]['crop_stop']}
|
75 |
+
with torch.no_grad():
|
76 |
+
pred, X_mag, X_phase = inference(X_spec_m,self.device,self.model, aggressiveness,self.data)
|
77 |
+
# Postprocess
|
78 |
+
if self.data['postprocess']:
|
79 |
+
pred_inv = np.clip(X_mag - pred, 0, np.inf)
|
80 |
+
pred = spec_utils.mask_silence(pred, pred_inv)
|
81 |
+
y_spec_m = pred * X_phase
|
82 |
+
v_spec_m = X_spec_m - y_spec_m
|
83 |
+
|
84 |
+
if (ins_root is not None):
|
85 |
+
if self.data['high_end_process'].startswith('mirroring'):
|
86 |
+
input_high_end_ = spec_utils.mirroring(self.data['high_end_process'], y_spec_m, input_high_end, self.mp)
|
87 |
+
wav_instrument = spec_utils.cmb_spectrogram_to_wave(y_spec_m, self.mp,input_high_end_h, input_high_end_)
|
88 |
+
else:
|
89 |
+
wav_instrument = spec_utils.cmb_spectrogram_to_wave(y_spec_m, self.mp)
|
90 |
+
print ('%s instruments done'%name)
|
91 |
+
wavfile.write(os.path.join(ins_root, 'instrument_{}.wav'.format(name) ), self.mp.param['sr'], (np.array(wav_instrument)*32768).astype("int16")) #
|
92 |
+
if (vocal_root is not None):
|
93 |
+
if self.data['high_end_process'].startswith('mirroring'):
|
94 |
+
input_high_end_ = spec_utils.mirroring(self.data['high_end_process'], v_spec_m, input_high_end, self.mp)
|
95 |
+
wav_vocals = spec_utils.cmb_spectrogram_to_wave(v_spec_m, self.mp, input_high_end_h, input_high_end_)
|
96 |
+
else:
|
97 |
+
wav_vocals = spec_utils.cmb_spectrogram_to_wave(v_spec_m, self.mp)
|
98 |
+
print ('%s vocals done'%name)
|
99 |
+
wavfile.write(os.path.join(vocal_root , 'vocal_{}.wav'.format(name) ), self.mp.param['sr'], (np.array(wav_vocals)*32768).astype("int16"))
|
100 |
+
|
101 |
+
if __name__ == '__main__':
|
102 |
+
device = 'cuda'
|
103 |
+
is_half=True
|
104 |
+
model_path='uvr5_weights/2_HP-UVR.pth'
|
105 |
+
pre_fun = _audio_pre_(model_path=model_path,device=device,is_half=True)
|
106 |
+
audio_path = 'audio.aac'
|
107 |
+
save_path = 'opt'
|
108 |
+
pre_fun._path_audio_(audio_path , save_path,save_path)
|
test_dataset.py
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import os
|
3 |
+
from pydub import AudioSegment
|
4 |
+
|
5 |
+
from nltk.tokenize import TweetTokenizer
|
6 |
+
word_tokenize = TweetTokenizer().tokenize
|
7 |
+
|
8 |
+
from gemini_normalize import call_api
|
9 |
+
|
10 |
+
import phonemizer
|
11 |
+
global_phonemizer = phonemizer.backend.EspeakBackend(language='vi', preserve_punctuation=True, with_stress=True,language_switch='remove-flags',words_mismatch='ignore')
|
12 |
+
|
13 |
+
def has_numbers(inputString):
|
14 |
+
return any(char.isdigit() for char in inputString)
|
15 |
+
def generate(root_path,parquet_file):
|
16 |
+
total_duration = 0
|
17 |
+
|
18 |
+
df = pd.read_parquet(root_path+"/"+parquet_file, engine='fastparquet')
|
19 |
+
new_df = pd.DataFrame(columns=['audio.path', 'text','speaker_id'])
|
20 |
+
for index, row in df.iterrows():
|
21 |
+
if index < 3000:
|
22 |
+
continue
|
23 |
+
file= df.loc[index, 'audio.path']
|
24 |
+
text = df.loc[index, 'text']
|
25 |
+
|
26 |
+
audio = AudioSegment.from_wav(file)
|
27 |
+
if len(audio)/1000.0>2:
|
28 |
+
total_duration += len(audio)
|
29 |
+
new_df = new_df.append({'audio.path':file,'text':text,'speaker_id':0},ignore_index=True)
|
30 |
+
|
31 |
+
|
32 |
+
if total_duration/(1000*60*6)>=1:
|
33 |
+
print(new_df.head())
|
34 |
+
new_df =new_df.reset_index(drop=True)
|
35 |
+
new_df.to_parquet(root_path+"/"+"Xanh24h_1h_test.parquet", engine='fastparquet')
|
36 |
+
break
|
37 |
+
|
38 |
+
|
39 |
+
def normalize_text(parquet_file):
|
40 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
41 |
+
req = []
|
42 |
+
print(df.shape[0]-1)
|
43 |
+
dem = 0
|
44 |
+
for index, row in df.iterrows():
|
45 |
+
text = df.loc[index, 'text']
|
46 |
+
req.append(text)
|
47 |
+
# print(index)
|
48 |
+
if len(req)==50 or index == df.shape[0]-1:
|
49 |
+
res = call_api(str(req))
|
50 |
+
|
51 |
+
for idx,r in enumerate(res):
|
52 |
+
df.loc[50*dem+idx, 'normal_text'] = r
|
53 |
+
dem+=1
|
54 |
+
req = []
|
55 |
+
for index, row in df.iterrows():
|
56 |
+
if has_numbers(df.loc[index, 'normal_text']):
|
57 |
+
print("has number",df.loc[index, 'normal_text'])
|
58 |
+
elif df.loc[index, 'normal_text'] != df.loc[index, 'text'] and not has_numbers(df.loc[index, 'text']):
|
59 |
+
print(df.loc[index, 'normal_text'])
|
60 |
+
print(df.loc[index, 'text'])
|
61 |
+
df.loc[index, 'normal_text'] = df.loc[index, 'text']
|
62 |
+
df.to_parquet(parquet_file, engine='fastparquet')
|
63 |
+
|
64 |
+
def word_process(parquet_path):
|
65 |
+
df = pd.read_parquet(parquet_path, engine='fastparquet')
|
66 |
+
for index, row in df.iterrows():
|
67 |
+
text = df.loc[index, 'normal_text']
|
68 |
+
|
69 |
+
text = word_tokenize(text)
|
70 |
+
text = ' '.join(text)
|
71 |
+
|
72 |
+
ps = global_phonemizer.phonemize([text])
|
73 |
+
|
74 |
+
df.loc[index, 'phonemes'] = ps[0]
|
75 |
+
|
76 |
+
df.to_parquet(parquet_path, engine='fastparquet')
|
77 |
+
|
78 |
+
def copy_audio(parquet_file):
|
79 |
+
import shutil
|
80 |
+
df = pd.read_parquet(parquet_file, engine='fastparquet')
|
81 |
+
for index, row in df.iterrows():
|
82 |
+
file= df.loc[index, 'audio.path']
|
83 |
+
shutil.copy2(file, file.replace("dataset","data"))
|
84 |
+
if __name__ == "__main__":
|
85 |
+
# generate("dataset","Xanh24h.parquet")
|
86 |
+
# normalize_text("dataset/Xanh24h_1h_test.parquet")
|
87 |
+
# read("dataset/Xanh24h_1h.parquet")
|
88 |
+
# word_process("dataset/Xanh24h_1h_test.parquet")
|
89 |
+
# copy_audio("dataset/Xanh24h_1h_test.parquet")
|
90 |
+
pass
|
text_nomalize.py
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
|
3 |
+
from nltk.tokenize import TweetTokenizer
|
4 |
+
from nltk.tokenize.treebank import TreebankWordDetokenizer
|
5 |
+
word_tokenize = TweetTokenizer().tokenize
|
6 |
+
|
7 |
+
from converters.Date import DateVietnamese
|
8 |
+
from converters.Time import Time
|
9 |
+
from converters.Money import Money
|
10 |
+
from converters.Fraction import Fraction
|
11 |
+
from converters.Telephone import TelephoneVietnamese
|
12 |
+
from converters.Cardinal import CardinalVietnamese
|
13 |
+
from converters.Decimal import Decimal
|
14 |
+
from converters.Range import Range
|
15 |
+
from converters.Meansure import Measure
|
16 |
+
|
17 |
+
labels ={
|
18 |
+
'DATE': DateVietnamese(),
|
19 |
+
'TIME':Time(),
|
20 |
+
'MONEY':Money(),
|
21 |
+
'FRACTION':Fraction(),
|
22 |
+
'TELEPHONE':TelephoneVietnamese(),
|
23 |
+
'CARDINAL':CardinalVietnamese(),
|
24 |
+
'DECIMAL':Decimal(),
|
25 |
+
'RANGE' :Range(),
|
26 |
+
'MEANSURE': Measure()
|
27 |
+
}
|
28 |
+
def has_numbers(inputString):
|
29 |
+
return any(char.isdigit() for char in inputString)
|
30 |
+
def has_date(inputString):
|
31 |
+
if "/" not in inputString:
|
32 |
+
return False
|
33 |
+
splt = inputString.split("/")
|
34 |
+
for i in splt:
|
35 |
+
if not i.isdigit():
|
36 |
+
return False
|
37 |
+
if len(splt) >3 :
|
38 |
+
return False
|
39 |
+
if len(splt) == 2:
|
40 |
+
month = int(splt[0])
|
41 |
+
year = int(splt[1])
|
42 |
+
if month >12 or year > 2200 or month <1:
|
43 |
+
return False
|
44 |
+
if len(splt)==3:
|
45 |
+
day =int(splt[0])
|
46 |
+
month = int(splt[1])
|
47 |
+
year =int(splt[2])
|
48 |
+
if day >31 or month > 12 or year >2200 or day < 1 or month <1:
|
49 |
+
return False
|
50 |
+
return True
|
51 |
+
|
52 |
+
def is_time(text):
|
53 |
+
if ":" not in text:
|
54 |
+
return False
|
55 |
+
if "-" in text:
|
56 |
+
text = text[:-1]
|
57 |
+
splt = text.split(":")
|
58 |
+
if len(splt)>3 or '' in splt:
|
59 |
+
return False
|
60 |
+
elif len(splt)==2:
|
61 |
+
HH,MM = int(splt[0]),int(splt[1])
|
62 |
+
if HH >24 or MM >60:
|
63 |
+
return False
|
64 |
+
elif len(splt) ==3:
|
65 |
+
HH,MM,SS = int(splt[0]),int(splt[1]),int(splt[2])
|
66 |
+
if HH>24 or MM>60 or SS>100:
|
67 |
+
return False
|
68 |
+
|
69 |
+
return True
|
70 |
+
def is_money(inputString):
|
71 |
+
return inputString.startswith(('$', '€', '£', '¥'))
|
72 |
+
def is_fraction(inputString):
|
73 |
+
return "/" in inputString
|
74 |
+
def is_decimal(inputString):
|
75 |
+
return "." in inputString
|
76 |
+
def is_cardinal(inputString):
|
77 |
+
return "," in inputString or len(inputString) <= 3
|
78 |
+
def is_range(inputString) :
|
79 |
+
return "-" in inputString
|
80 |
+
def is_telephone(inputString):
|
81 |
+
if inputString.startswith(("19", "18", "0")) and len(inputString)>4:
|
82 |
+
return True
|
83 |
+
def is_meansure(text):
|
84 |
+
if text in labels['MEANSURE'].custom_dict:
|
85 |
+
return True
|
86 |
+
def normalize_single(text,previous=""):
|
87 |
+
|
88 |
+
if has_numbers(text):
|
89 |
+
|
90 |
+
if has_date(text):
|
91 |
+
text = labels["DATE"].convert_date(text)
|
92 |
+
|
93 |
+
elif is_time(text):
|
94 |
+
if text.endswith("-"):
|
95 |
+
kq = labels['TIME'].convert(text[:-1])
|
96 |
+
kq += " đến"
|
97 |
+
else:
|
98 |
+
kq = labels['TIME'].convert(text)
|
99 |
+
text =kq
|
100 |
+
|
101 |
+
elif is_money(text):
|
102 |
+
text = labels['MONEY'].convert(text)
|
103 |
+
|
104 |
+
elif is_decimal(text):
|
105 |
+
text = labels['DECIMAL'].convert(text)
|
106 |
+
elif is_telephone(text):
|
107 |
+
text =labels['TELEPHONE'].convert(text)
|
108 |
+
elif is_cardinal(text):
|
109 |
+
text = labels['CARDINAL'].convert(text)
|
110 |
+
elif is_range(text):
|
111 |
+
text = labels['RANGE'].convert(text)
|
112 |
+
|
113 |
+
if is_fraction(text):
|
114 |
+
text = labels['FRACTION'].convert(text)
|
115 |
+
if has_numbers(text):
|
116 |
+
text = labels['CARDINAL'].convert(text)
|
117 |
+
|
118 |
+
text = text.replace("%", " phần trăm ")
|
119 |
+
text = text.replace("&", " và ")
|
120 |
+
text = text.replace("°"," độ ")
|
121 |
+
return text
|
122 |
+
if __name__ == "__main__":
|
123 |
+
v ="90000"
|
124 |
+
v =word_tokenize(v)
|
125 |
+
print(v)
|
126 |
+
for i in v:
|
127 |
+
te =normalize_single(i)
|
128 |
+
print(i, te)
|
upload_huggingface.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from huggingface_hub import HfApi
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
load_dotenv()
|
4 |
+
|
5 |
+
import os
|
6 |
+
# Lấy giá trị token
|
7 |
+
a =input()
|
8 |
+
api = HfApi(token=a)
|
9 |
+
print("load")
|
10 |
+
|
11 |
+
api.upload_folder(
|
12 |
+
folder_path="",
|
13 |
+
repo_id="namkuner/Generate_Audio",
|
14 |
+
repo_type="model",
|
15 |
+
|
16 |
+
)
|