China Movies Speak Khmer.
May 07, 2026
import os, whisper, asyncio, edge_tts, re
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/LONG_DUB_{Video_Name}"
translator = Translator()
def professional_khmer_filter(text):
try:
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: return None, None
voice = "km-KH-PisethNeural" # ម្ចាស់គ្រូអាចកែជា Sreymom បើជាតួស្រី
tmp = f"tmp_{index}_{start}.mp3"
communicate = edge_tts.Communicate(kh_text, voice, rate="+7%")
await communicate.save(tmp)
audio = AudioFileClip(tmp).set_start(start).volumex(4.5)
if audio.duration > duration:
return vfx.speedx(audio, factor=audio.duration/duration).set_duration(duration), tmp
return audio, tmp
except:
return None, None
async def start_dubbing():
if not os.path.exists(VIDEO_PATH):
print("❌ រកមិនឃើញ File វីដេអូទេម្ចាស់គ្រូ!")
return
# ១. ប្រើ Whisper ស្កែន (សម្រាប់រឿងវែង គួរប្រើ 'base' បើ RAM តិច ឬ 'medium' បើមាន GPU ខ្លាំង)
print("🔍 កំពុងវិភាគសាច់រឿងវែង... (សូមរង់ចាំបន្តិច)")
model = whisper.load_model("medium")
transcribe = model.transcribe(VIDEO_PATH, task="transcribe", language="zh")
# ២. រៀបចំ Segment
merged_segments = transcribe['segments']
video = VideoFileClip(VIDEO_PATH)
audio_tracks = [video.audio.volumex(0.15)]
temp_files = []
print(f"🎙️ ចាប់ផ្ដើម Dubbing ចំនួន {len(merged_segments)} ឃ្លា...")
# ៣. ប្រើ Loop ធម្មតាជំនួសឱ្យ asyncio.gather ដើម្បីការពារការគាំង RAM
for i, s in enumerate(merged_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)
# បង្ហាញ Progress ឱ្យម្ចាស់គ្រូដឹង
if i % 10 == 0:
print(f"⏳ ធ្វើបាន {i}/{len(merged_segments)} ឃ្លាហើយ...")
# ៤. រួមបញ្ចូលគ្នា
print("🎬 កំពុងបូកបញ្ចូលសំឡេង និង Export វីដេអូកម្រិតច្បាស់...")
final_audio = CompositeAudioClip(audio_tracks)
final_video = video.set_audio(final_audio)
# ប្រើ threads=4 ដើម្បីឱ្យវា Export លឿន
final_video.write_videofile(OUTPUT_PATH, codec="libx264", audio_codec="aac", fps=video.fps, threads=4)
# ៥. សម្អាត File
video.close() # បិទ File ដើម្បីឱ្យលុប Temp បាន
for f in temp_files:
try: os.remove(f)
except: pass
print(f"✅ រួចរាល់ហើយម្ចាស់គ្រូ! វីដេអូរឿងវែងស្ថិតនៅ៖ {OUTPUT_PATH}")
# រត់កម្មវិធី
await start_dubbing()
- Blogger Comment
- Facebook Comment
0 comments:
Post a Comment