🚀 កូដ BM7 Ultimate Smart Dubbing (V3 - Professional Edition)
China Movies Speak Khmer.
May 11, 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_V3_{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:
if not text or len(text.strip()) < 1: return ""
# ១. លុបពាក្យដដែលៗចេញពី Whisper (Anti-Hallucination)
text = re.sub(r'\b(\w+)( \1\b)+', r'\1', text)
# ២. បកប្រែ
raw_kh = translator.translate(text, src='zh-cn', dest='km').text
if not raw_kh: return ""
# ៣. បន្សុទ្ធអត្ថបទឱ្យស៊ីសាច់រឿង
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()).strip()
except: return ""
async def generate_ultimate_audio(text, start, duration, index):
try:
kh_text = professional_khmer_filter(text)
if not kh_text: return None, None
voice = detect_gender(kh_text)
tmp = f"tmp_{index}.mp3"
# កែសម្រួលឱ្យមាន Pitch ស្រទន់ និងល្បឿនអានសមរម្យ
communicate = edge_tts.Communicate(kh_text, voice, rate="+2%", pitch="+15Hz")
await communicate.save(tmp)
audio = AudioFileClip(tmp).set_start(start).volumex(5.5).audio_fadein(0.1).audio_fadeout(0.1)
# --- Smart Speed Control ---
actual_dur = audio.duration
target_dur = duration
if actual_dur > target_dur:
# បើអានវែងពេក ឱ្យវាបង្កើនល្បឿនឱ្យត្រូវនឹងមាត់ (Lip-sync)
audio = vfx.speedx(audio, factor=actual_dur/target_dur).set_duration(target_dur)
elif actual_dur < (target_dur * 0.5):
# បើអានខ្លីពេក (លឿនពេក) ឱ្យវាពន្យឺតមកវិញខ្លះដើម្បីឱ្យរលូន
audio = vfx.speedx(audio, factor=actual_dur/(target_dur * 0.7)).set_duration(target_dur * 0.7)
return audio, tmp
except: return None, None
async def start_dubbing():
if not os.path.exists(VIDEO_PATH):
print("❌ រកមិនឃើញ File វីដេអូទេម្ចាស់គ្រូ!"); return
print("🚀 កំពុងដំណើរការខួរក្បាល AI (Whisper Medium)...")
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)
segments = transcribe['segments']
# --- Smart Merging Logic (បញ្ចូលឃ្លាដែលនៅកៀកគ្នា) ---
merged_segments = []
if segments:
curr = segments[0]
for next_s in segments[1:]:
# បើឃ្លាទី២ ចាប់ផ្ដើមក្រោយឃ្លាទី១ ចប់មិនដល់ ០.៦ វិនាទី ឱ្យបញ្ចូលគ្នា
if next_s['start'] - curr['end'] < 0.6:
curr['text'] += " " + next_s['text']
curr['end'] = next_s['end']
else:
merged_segments.append(curr)
curr = next_s
merged_segments.append(curr)
video = VideoFileClip(VIDEO_PATH)
audio_tracks = [video.audio.volumex(0.12)] # Background Music 12%
temp_files = []
print(f"🎙️ កំពុងជប់សំឡេងបកប្រែចំនួន {len(merged_segments)} ឃ្លាធំៗ...")
for i, s in enumerate(merged_segments):
aud, path = await generate_ultimate_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(merged_segments))*100)}%...")
print("🎬 កំពុង Export វីដេអូកម្រិតច្បាស់ (High Quality Rendering)...")
final_video = video.set_audio(CompositeAudioClip(audio_tracks))
final_video.write_videofile(OUTPUT_PATH, codec="libx264", audio_codec="aac", threads=4, fps=video.fps)
video.close()
for f in temp_files:
try: os.remove(f)
except: pass
print(f"✅ ជោគជ័យ! ម្ចាស់គ្រូអាចទៅឆែកមើលស្នាដៃបាននៅ៖ {OUTPUT_PATH}")
if __name__ == "__main__":
await start_dubbing()
- Blogger Comment
- Facebook Comment
0 comments:
Post a Comment