China Movies Speak Khmer.
May 10, 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_ULTIMATE_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
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)
# លុបសញ្ញាខណ្ឌដែលនាំឱ្យ AI អានឈប់យូរពេក
raw_kh = re.sub(r'[.!?៖។]', ' ', raw_kh)
return " ".join(raw_kh.split()) # លុប Space ដែលលើស
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="+10%", pitch="-1Hz")
await communicate.save(tmp)
# បន្ថែម Fade ឱ្យសំឡេងចូលមកស្រទន់
audio = AudioFileClip(tmp).set_start(start).volumex(5.2).audio_fadein(0.05).audio_fadeout(0.05)
# គ្រប់គ្រងល្បឿន
actual_dur = audio.duration
target_dur = duration
if actual_dur > target_dur:
audio = vfx.speedx(audio, factor=actual_dur/target_dur).set_duration(target_dur)
elif actual_dur < (target_dur * 0.6):
# បើខ្លីពេក ឱ្យវាអានមួយៗ (Slow down)
audio = vfx.speedx(audio, factor=actual_dur/(target_dur * 0.8)).set_duration(target_dur * 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 (Medium Model)...")
device = "cuda" if torch.cuda.is_available() else "cpu"
model = whisper.load_model("medium").to(device)
# កំណត់កម្រិតស្ដាប់ឱ្យហ្មត់ចត់
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.10)] # បន្ថយសំឡេងដើមមកត្រឹម ១០%
temp_files = []
print(f"🎙️ កំពុងផលិតសំឡេងបកប្រែ {len(segments)} ឃ្លា...")
# ប្រើ Loop ដើម្បីស្ថេរភាព RAM
for i, s in enumerate(segments):
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 % 25 == 0:
print(f"⏳ Progress: {round((i/len(segments))*100)}%...")
print("🎬 កំពុងចងក្រងវីដេអូសម្រេច (High Quality)...")
final_audio = CompositeAudioClip(audio_tracks)
final_video = video.set_audio(final_audio)
# ប្រើ threads=4 ដើម្បីល្បឿន និង preset=ultrafast បើចង់បានលឿន
final_video.write_videofile(OUTPUT_PATH, codec="libx264", audio_codec="aac", threads=4, fps=video.fps)
# សម្អាត File បណ្ដោះអាសន្ន
video.close()
for f in temp_files:
try:
if os.path.exists(f): os.remove(f)
except: pass
print(f"✅ ជោគជ័យមហាអស្ចារ្យម្ចាស់គ្រូ! វីដេអូរួចរាល់៖ {OUTPUT_PATH}")
if __name__ == "__main__":
# បើកដំណើរការ Async
loop = asyncio.get_event_loop()
loop.run_until_complete(start_dubbing())
- Blogger Comment
- Facebook Comment
0 comments:
Post a Comment