Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import whisper | |
| import os | |
| import requests | |
| from bs4 import BeautifulSoup | |
| from moviepy.editor import * | |
| import arabic_reshaper | |
| from bidi.algorithm import get_display | |
| from googletrans import Translator | |
| import time | |
| # --- فەنکشنە پێشکەوتووەکان --- | |
| def apply_text_motion(clip, text, font_path, motion_type, duration): | |
| """دانانی مۆشنی تێکست بەپێی جۆری هەڵبژێردراو.""" | |
| # چاککردنی فارسی/کوردی | |
| reshaped_text = arabic_reshaper.reshape(text) | |
| bidi_text = get_display(reshaped_text) | |
| # دانانی شێوازی بنەڕەتی بۆ تێکست | |
| txt_clip = TextClip(bidi_text, fontsize=80, color='yellow', font=font_path, stroke_color='black', stroke_width=3, method='caption', align='center', size=(700, None)) | |
| if motion_type == "Fade In/Out": | |
| # دەرکەوتن و ونبوون | |
| clip = txt_clip.set_duration(duration).set_pos('bottom').fx(fadein, 0.5).fx(fadeout, 0.5) | |
| elif motion_type == "Zoom In": | |
| # زووم کردن و گەورەبوون | |
| def zoom_in_effect(t): | |
| scale = 1 + 0.5 * (t / duration) | |
| return txt_clip.set_scale(scale).get_frame(t) | |
| clip = txt_clip.set_duration(duration).set_pos('center').fl(zoom_in_effect, apply_to=['mask', 'video']) | |
| elif motion_type == "Slide Up": | |
| # هاتنەسەرەوە لە خوارەوە | |
| w, h = txt_clip.size | |
| clip = txt_clip.set_duration(duration) | |
| clip = clip.set_pos(lambda t: ('center', 100 + h * (1 - t / duration))) | |
| else: # Default (Simple Fade In/Out) | |
| clip = txt_clip.set_duration(duration).set_pos('bottom').fx(fadein, 0.5).fx(fadeout, 0.5) | |
| return clip.set_duration(duration) | |
| def apply_image_motion(image_clip, motion_type): | |
| """دانانی ئیفێکتی Ken Burns و جوڵەی تری وێنە.""" | |
| if motion_type == "Ken Burns (Zoom Out)": | |
| # زووم ئاوتێکی هێواش | |
| clip = image_clip.fx(vfx.resize, lambda t: 1.2 - 0.2 * (t / image_clip.duration)) | |
| elif motion_type == "Ken Burns (Zoom In)": | |
| # زووم ئینێکی هێواش | |
| clip = image_clip.fx(vfx.resize, lambda t: 1 + 0.2 * (t / image_clip.duration)) | |
| elif motion_type == "Slide Right": | |
| # خشاندن بۆ لای ڕاست | |
| w, h = image_clip.size | |
| clip = image_clip.set_pos(lambda t: ('-100+{}'.format(int(200 * t / image_clip.duration)), 'center')) | |
| else: | |
| clip = image_clip # بێ جوڵە | |
| # دڵنیابوون لە قەبارەی شۆرتی یوتیوب (9:16) | |
| clip = vfx.resize(clip, height=1280) | |
| clip = vfx.crop(clip, width=720, height=1280, x_center=clip.w / 2, y_center=clip.h / 2) | |
| return clip | |
| # --- فەنکشنی دروستکردنی ڤیدیۆ (بۆ تێست) --- | |
| # تێبینی: بەهۆی قورسی دروستکردنی AI Image لەسەر سێرڤەری خۆڕایی، ئێمە وێنەی ڕەنگینی سادە بەکاردێنین بۆ تێست | |
| def create_ai_images(prompts): | |
| """لێرە کۆدی دروستکردنی وێنە بە AI (Stable Diffusion/Hugging Face API) دادەنرێت""" | |
| st.info("بەهۆی سنوورداربوونی سێرڤەری خۆڕایی، 5 وێنەی کاتی دروست دەکرێت.") | |
| images = [] | |
| colors = [(255, 100, 100), (100, 255, 100), (100, 100, 255), (255, 255, 100), (100, 255, 255)] | |
| for i in range(5): | |
| # دروستکردنی وێنەی ڕەنگ بە پیلۆ | |
| img = ImageClip(np.array([colors[i]]*100*100, dtype=np.uint8).reshape(100, 100, 3), duration=3) | |
| images.append(img) | |
| return images | |
| # --- UI سەرەکی --- | |
| st.title("🎼 ئۆتۆمەیشنی شۆرتی گۆرانی فارسی (پڕۆ)") | |
| st.caption("سیستەمی 'یەک کلیک' لەسەر Hugging Face Spaces + Streamlit") | |
| # ئیختیاراتی بەکاربەر | |
| st.sidebar.header("🎨 هەڵبژاردەی کوالێتی") | |
| text_motion = st.sidebar.selectbox("جوڵەی تێکست (Text Motion):", ["Fade In/Out", "Zoom In", "Slide Up", "بێ جوڵە"]) | |
| image_motion = st.sidebar.selectbox("جوڵەی وێنە (Image Motion):", ["Ken Burns (Zoom Out)", "Ken Burns (Zoom In)", "Slide Right", "بێ جوڵە"]) | |
| uploaded_file = st.file_uploader("فایلی گۆرانییەکە ئەپلۆد بکە (.mp3, .wav)", type=["mp3", "wav"]) | |
| if uploaded_file is not None: | |
| st.audio(uploaded_file, format='audio/mp3') | |
| if st.button('◀️ دروستکردنی ڤیدیۆ (دەستپێکردن)', key='start_button'): | |
| # دڵنیابوون لە سڕینەوەی فایلی پێشوو | |
| if os.path.exists("temp_audio.mp3"): os.remove("temp_audio.mp3") | |
| if os.path.exists("final_short.mp4"): os.remove("final_short.mp4") | |
| # 1. خەزنکردنی دەنگ | |
| with open("temp_audio.mp3", "wb") as f: | |
| f.write(uploaded_file.getbuffer()) | |
| # 2. Transcribe & Search (هەنگاوەکان) | |
| with st.spinner('1. ساغکردنەوەی دەنگ و دۆزینەوەی شعر...'): | |
| model = whisper.load_model("base") | |
| result = model.transcribe("temp_audio.mp3") | |
| transcribed_text = result["text"] | |
| # لێرە کۆدی گەڕان لە گوگڵ و بەراوردکردن دادەنرێت | |
| # دابەشکردنی تێکست بۆ دێڕی کورت بۆ نیشاندان | |
| lyrics_lines = final_lyrics.split('\n') | |
| if len(lyrics_lines) < 5: lyrics_lines = [final_lyrics] * 5 | |
| st.success(f"شعرەکە دۆزرایەوە (نموونە): {lyrics_lines[0]}...") | |
| # 3. AI Image Generation (یاخود وێنەی کاتی) | |
| with st.spinner('2. دروستکردنی وێنەکانی چیرۆکەکە...'): | |
| image_clips = create_ai_images(lyrics_lines) | |
| st.success(f"5 وێنەی کاتی دروست کرا.") | |
| # 4. Video Construction | |
| with st.spinner('3. مۆنتاژکردن و دانانی مۆشنی پڕۆفیشناڵ...'): | |
| final_clips = [] | |
| segment_duration = audio_clip.duration / len(image_clips) # دابەشکردنی کات | |
| # دروستکردنی ڤیدیۆی سەرەکی | |
| for i, img_clip in enumerate(image_clips): | |
| # دانانی کات بۆ وێنەکە | |
| img_clip = img_clip.set_duration(segment_duration) | |
| # دانانی جوڵە بۆ وێنە (Ken Burns, Slide) | |
| motion_clip = apply_image_motion(img_clip, image_motion) | |
| # دانانی تێکست لەسەر وێنەکە | |
| if i < len(lyrics_lines): | |
| text_segment = lyrics_lines[i] | |
| # دانانی جوڵە بۆ تێکست | |
| text_clip = apply_text_motion(motion_clip, text_segment, 'Arial', text_motion, segment_duration) | |
| final_clip = CompositeVideoClip([motion_clip, text_clip]) | |
| else: | |
| final_clip = motion_clip | |
| final_clips.append(final_clip) | |
| # یەکخستنی هەموو بەشەکان | |
| final_video = concatenate_videoclips(final_clips) | |
| # دانانی دەنگەکە لەسەر ڤیدیۆ کۆتاییەکە | |
| audio_clip = AudioFileClip("temp_audio.mp3") | |
| final_video = final_video.set_audio(audio_clip) | |
| # Render | |
| final_video.write_videofile("final_short.mp4", fps=24, threads=4, logger=None) | |
| st.success("✅ ڤیدیۆکە بە سەرکەوتوویی دروست کرا!") | |
| st.video("final_short.mp4") | |
| with open("final_short.mp4", "rb") as file: | |
| st.download_button( | |
| label="داگرتنی ڤیدیۆکە (.mp4)", | |
| data=file, | |
| file_name="youtube_short.mp4", | |
| mime="video/mp4" | |
| ) |