China Movies Speak Khmer.
May 09, 2026
import os, whisper, asyncio, edge_tts, re, torch
from googletrans import Translator
from moviepy.editor import VideoFileClip, AudioFileClip, CompositeAudioClip
import moviepy.video.fx.all as vfx
# --- ⚙️ ការកំណត់ ---
Video_Name = "movie.mp4"
VIDEO_PATH = f"input_video/{Video_Name}"
OUTPUT_PATH = f"final_result/BM7_STABLE_DUB_{Video_Name}"
translator = Translator()
def detect_gender(text):
# បែងចែកភេទតាមពាក្យគន្លឹះ
female_keywords = ['នាង', 'ស្រី', 'អូន', 'អ្នកនាង', 'កញ្ញា', 'ម៉ាក់', 'យាយ']
if any(word in text for word in female_keywords):
return "km-KH-SreymomNeural"
return "km-KH-PisethNeural"
def professional_khmer_filter(text):
try:
# លុបពាក្យដដែលៗដែលចេញពី Whisper (Hallucination Filter)
text = re.sub(r'\b(\w+)( \1\b)+', r'\1', text)
raw_kh = translator.translate(text, src='zh-cn', dest='km').text
corrections = {
"អ្នក": "ឯង", "ខ្ញុំ": "យើង", "សួស្តី": "ជម្រាបសួរ",
"អរគុណ": "អរគុណច្រើន", "មែនទេ": "មែនអត់?", "ពិតជា": "ពិតមែនហើយ"
}
for old, new in corrections.items():
raw_kh = raw_kh.replace(old, new)
return re.sub(r'[.,!?]', ' ', raw_kh).strip()
except: return ""
async def generate_smooth_audio(text, start, duration, index):
try:
kh_text = professional_khmer_filter(text)
if not kh_text or len(kh_text) < 2: return None, None
voice = detect_gender(kh_text)
tmp = f"tmp_{index}.mp3"
# កែសម្រួល Pitch និង Rate ឱ្យស្រទន់
communicate = edge_tts.Communicate(kh_text, voice, rate="+7%", pitch="-1Hz")
await communicate.save(tmp)
audio = AudioFileClip(tmp).set_start(start).volumex(5.0)
# ត្រួតពិនិត្យល្បឿន៖ បើលឿនពេក ឬយឺតពេក ឱ្យវាតម្រូវតាម Duration
target_duration = duration
if audio.duration > target_duration:
# បើអានវែងជាងសាច់រឿង ឱ្យវាបង្កើនល្បឿនបន្តិច
audio = vfx.speedx(audio, factor=audio.duration/target_duration).set_duration(target_duration)
elif audio.duration < (target_duration * 0.7):
# បើអានខ្លីពេក (ញាប់ពេក) ឱ្យវាពន្យឺតមកវិញខ្លះដើម្បីឱ្យស្រួលស្ដាប់
audio = vfx.speedx(audio, factor=audio.duration/(target_duration * 0.8)).set_duration(target_duration * 0.8)
return audio, tmp
except: return None, None
async def start_dubbing():
if not os.path.exists(VIDEO_PATH):
print("❌ រកមិនឃើញ File ទេ!"); return
print("🚀 កំពុងដាស់ម៉ាស៊ីន AI កម្រិតខ្ពស់...")
device = "cuda" if torch.cuda.is_available() else "cpu"
model = whisper.load_model("medium").to(device)
# បន្ថែម Parameters ដើម្បីបំបាត់ពាក្យដដែលៗ
transcribe = model.transcribe(
VIDEO_PATH,
task="transcribe",
language="zh",
temperature=0, # បំបាត់ការទាយរាយមាយ
beam_size=5, # ពិនិត្យពាក្យឱ្យហ្មត់ចត់
compression_ratio_threshold=2.4 # ទប់ស្កាត់ពាក្យដដែលៗ
)
segments = transcribe['segments']
video = VideoFileClip(VIDEO_PATH)
audio_tracks = [video.audio.volumex(0.12)]
temp_files = []
print(f"🎙️ ចាប់ផ្ដើមផលិតសំឡេងចំនួន {len(segments)} ឃ្លា...")
for i, s in enumerate(segments):
# ប្រើ await ដើម្បីឱ្យវាធ្វើម្ដងមួយៗ ការពារការគាំង RAM លើរឿងវែង
aud, path = await generate_smooth_audio(s['text'], s['start'], s['end']-s['start'], i)
if aud:
audio_tracks.append(aud)
temp_files.append(path)
if i % 20 == 0:
print(f"⏳ រួចរាល់ {round((i/len(segments))*100)}%...")
print("🎬 កំពុង Export វីដេអូសម្រេច (Threads=4)...")
final_audio = CompositeAudioClip(audio_tracks)
final_video = video.set_audio(final_audio)
final_video.write_videofile(OUTPUT_PATH, codec="libx264", audio_codec="aac", threads=4)
# សម្អាត File
video.close()
for f in temp_files:
if os.path.exists(f): os.remove(f)
print(f"✅ ជោគជ័យមហាអស្ចារ្យ! វីដេអូរួចរាល់៖ {OUTPUT_PATH}")
if __name__ == "__main__":
await start_dubbing()
- Blogger Comment
- Facebook Comment
0 comments:
Post a Comment