|
|
|
|
|
import gradio as gr |
|
from deep_translator import GoogleTranslator |
|
import os |
|
import shutil |
|
import subprocess |
|
from PIL import Image, ImageDraw, ImageFont |
|
import re |
|
import uuid |
|
|
|
zip_file = "./fonts.zip" |
|
|
|
extract_to = "./fonts/" |
|
|
|
shutil.unpack_archive(zip_file, extract_to, 'zip') |
|
|
|
|
|
def tts_file_name(text): |
|
global temp_folder |
|
|
|
text = re.sub(r'[^a-zA-Z\s]', '', text) |
|
text = text.lower().strip() |
|
text = text.replace(" ", "_") |
|
|
|
truncated_text = text[:20] if len(text) > 20 else text if len(text) > 0 else "" |
|
|
|
|
|
random_string = uuid.uuid4().hex[:8].upper() |
|
|
|
|
|
file_name = f"{temp_folder}/{truncated_text}_{random_string}.mp4" |
|
return file_name |
|
|
|
temp_folder="./save_video" |
|
os.makedirs(temp_folder,exist_ok=True) |
|
|
|
def translate_text(text, target_language): |
|
try: |
|
translator = GoogleTranslator(source='auto', target=target_language) |
|
return translator.translate(text) |
|
except Exception as e: |
|
print(f"Translation error: {e}") |
|
return text |
|
|
|
|
|
ForeignLanguages = { |
|
"en": "English", "zh-CN": "Mandarin Chinese", "hi": "Hindi", "es": "Spanish", |
|
"fr": "French", "ar": "Standard Arabic", "bn": "Bengali", "pt": "Portuguese", |
|
"ru": "Russian", "ur": "Urdu", "id": "Indonesian", "de": "German", "ja": "Japanese", |
|
"pa": "Punjabi", "te": "Telugu", "tr": "Turkish", "ta": "Tamil", "vi": "Vietnamese", "ko": "Korean" |
|
} |
|
|
|
LocalIndianLanguages = { |
|
"en": "English","hi": "Hindi", "bn": "Bengali", "mr": "Marathi", "te": "Telugu", "ta": "Tamil", |
|
"gu": "Gujarati", "ur": "Urdu", "kn": "Kannada", "or": "Odia", "pa": "Punjabi", "ml": "Malayalam", |
|
"mai": "Maithili","ne": "Nepali","sa": "Sanskrit","doi": "Dogri","sd": "Sindhi" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
font_mapping = { |
|
"Arial-Bold.TTF": [ "it", "pt", "tr", "id"], |
|
"OpenSans-Bold.ttf": ["ru", "vi"], |
|
"Poppins-Bold.ttf": ["en","es","fr","hi","de"], |
|
"NotoSansJP-Bold.ttf":["ja"], |
|
"NotoSansBengali-Bold.ttf":["bn"], |
|
"NotoSansKR-Bold.ttf":["ko"], |
|
"NotoSansTamil-Bold.ttf":["ta"], |
|
"AnekTelugu-Bold.ttf":["te"], |
|
"BraahOne-Regular.ttf":["pa"], |
|
"NotoNastaliqUrdu-Bold.ttf":["ur"], |
|
"NotoSansSC-Bold.ttf":["zh-CN"], |
|
"NotoSansArabic-Bold.ttf":["ar","sd"], |
|
"NotoSansGujarati-Bold.ttf":["gu"], |
|
"NotoSansKannada-Bold.ttf":["kn"], |
|
"AnekOdia-Bold.ttf":["or"], |
|
"NotoSansMalayalam-Bold.ttf":["ml"], |
|
"NotoSans-Bold.ttf":["mr"] |
|
|
|
} |
|
|
|
|
|
|
|
def get_font_for_language(language): |
|
for font, languages in font_mapping.items(): |
|
if language in languages: |
|
return f"./fonts/{font}" |
|
return "./fonts/NotoSans-Bold.ttf" |
|
|
|
|
|
def create_image(text, language="en", font_size=100, text_color="#000000", bg_color="#FFFFFF", width=1024, height=1024, output_folder="./"): |
|
img = Image.new('RGB', (width, height), color=bg_color) |
|
draw = ImageDraw.Draw(img) |
|
|
|
font_path = get_font_for_language(language) |
|
print(font_path) |
|
font = ImageFont.truetype(font_path, font_size) |
|
|
|
|
|
|
|
|
|
|
|
bbox = draw.textbbox((0, 0), text, font=font) |
|
text_width, text_height = bbox[2] - bbox[0], bbox[3] - bbox[1] |
|
x, y = (width - text_width) // 2, (height - text_height) // 2 |
|
draw.text((x, y), text, fill=text_color, font=font) |
|
|
|
filename = os.path.join(output_folder, f"frame_{language}.png") |
|
img.save(filename) |
|
return filename |
|
|
|
|
|
import subprocess |
|
|
|
def get_video_duration(video_file): |
|
|
|
result = subprocess.run( |
|
['ffmpeg', '-i', video_file], |
|
stderr=subprocess.PIPE, |
|
stdout=subprocess.PIPE |
|
) |
|
|
|
|
|
output = result.stderr.decode() |
|
|
|
|
|
match = re.search(r'Duration: (\d+):(\d+):(\d+\.\d+)', output) |
|
|
|
if match: |
|
hours = int(match.group(1)) |
|
minutes = int(match.group(2)) |
|
seconds = float(match.group(3)) |
|
|
|
|
|
total_seconds = hours * 3600 + minutes * 60 + seconds |
|
return total_seconds |
|
else: |
|
raise ValueError("Could not extract video duration.") |
|
|
|
|
|
|
|
|
|
|
|
def generate_video(input_text, language_set, font_size, theme, canvas_size): |
|
width, height = map(int, canvas_size.split('x')) |
|
theme_colors = {"Black Background": ("#FFFFFF", "#000000"), "White Background": ("#000000", "#FFFFFF")} |
|
text_color, bg_color = theme_colors[theme] |
|
output_folder = "temp_frames" |
|
frames = "./frames" |
|
|
|
if os.path.exists(output_folder): |
|
shutil.rmtree(output_folder) |
|
os.makedirs(output_folder) |
|
if os.path.exists(frames): |
|
shutil.rmtree(frames) |
|
os.makedirs(frames) |
|
|
|
|
|
language_list = list(ForeignLanguages.keys()) if language_set == "Foreign Languages" else list(LocalIndianLanguages.keys()) |
|
image_files = [] |
|
|
|
FPS = 30 |
|
DURATION_PER_IMAGE = 0.5 |
|
FRAMES_PER_IMAGE = round(FPS * DURATION_PER_IMAGE) |
|
extra_frames = FRAMES_PER_IMAGE+10 |
|
frame_index = 0 |
|
|
|
for i, lang in enumerate(language_list): |
|
translated_text = translate_text(input_text, lang) if lang != 'en' else input_text |
|
img_path = create_image(translated_text, lang, font_size, text_color, bg_color, width, height, output_folder) |
|
|
|
|
|
frame_count = FRAMES_PER_IMAGE + extra_frames if i == len(language_list) - 1 else FRAMES_PER_IMAGE |
|
|
|
|
|
for _ in range(frame_count): |
|
frame_filename = os.path.join(frames, f"{frame_index:05d}.png") |
|
shutil.copy(img_path, frame_filename) |
|
frame_index += 1 |
|
|
|
|
|
output_video = "multi_language_video.mp4" |
|
subprocess.run([ |
|
"ffmpeg", "-y", "-r", str(FPS), "-i", f"{frames}/%05d.png", |
|
"-c:v", "libx264", "-pix_fmt", "yuv420p", output_video |
|
]) |
|
|
|
|
|
music_file = "./music.WAV" |
|
|
|
final_video = tts_file_name(input_text) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
video_duration = get_video_duration(output_video) |
|
|
|
fade_out_start = max(0, video_duration - 1) |
|
subprocess.run([ |
|
"ffmpeg", "-y", "-i", output_video, "-i", music_file, |
|
"-c:v", "libx264", "-c:a", "aac", "-strict", "experimental", |
|
"-af", f"afade=t=out:st={fade_out_start}:d=1", |
|
"-shortest", final_video |
|
]) |
|
|
|
|
|
shutil.rmtree(output_folder) |
|
shutil.rmtree(frames) |
|
return final_video, final_video |
|
|
|
|
|
def ui(): |
|
dummy_examples = [ |
|
["Hello", "Foreign Languages"], |
|
["No", "Local Indian Languages"] |
|
] |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("<center><h1 style='font-size: 40px;'>See Your Name in Different Languages</h1></center>") |
|
with gr.Row(): |
|
with gr.Column(): |
|
input_text = gr.Textbox(label='π Enter Your Name', lines=3) |
|
language_set = gr.Radio( |
|
["Foreign Languages", "Local Indian Languages"], |
|
label="πLanguage Set", |
|
value="Foreign Languages" |
|
) |
|
canvas_size = gr.Radio( |
|
["1920x1080", "1080x1920", "1024x1024"], |
|
value="1024x1024", |
|
label="π₯οΈ Canvas Size" |
|
) |
|
generate_btn = gr.Button('π Generate', variant='primary') |
|
|
|
with gr.Accordion('ποΈ Text Style', open=False): |
|
font_size = gr.Slider(20, 200, value=100, step=1, label="π Font Size") |
|
theme = gr.Radio(["Black Background", "White Background"], label="π¨ Theme", value="Black Background") |
|
|
|
with gr.Column(): |
|
download_video = gr.File(label="π₯ Download Video") |
|
play_video = gr.Video(label="π¬ Generated Video") |
|
|
|
|
|
input_list = [input_text, language_set, font_size, theme, canvas_size] |
|
output_list = [download_video, play_video] |
|
|
|
|
|
input_text.submit(generate_video, inputs=input_list, outputs=output_list) |
|
generate_btn.click(generate_video, inputs=input_list, outputs=output_list) |
|
|
|
|
|
gr.Examples(examples=dummy_examples, inputs=[input_text, language_set]) |
|
|
|
return demo |
|
|
|
|
|
def main(share=True, debug=True): |
|
demo = ui() |
|
demo.queue().launch(debug=debug, share=share) |
|
|
|
main() |
|
|