import os import gradio as gr import subprocess import cv2 from PIL import Image import google.generativeai as genai import base64 # ========== SETUP ========== def set_api_key(api_key): os.environ["GOOGLE_API_KEY"] = api_key genai.configure(api_key=api_key) # ========== TEXT TO IMAGE ========== def text_to_image(api_key, prompt, image_file, resolution): try: set_api_key(api_key) model = genai.GenerativeModel("imagen-3.0") if image_file: final_prompt = {"text": prompt, "image": Image.open(image_file)} else: final_prompt = prompt result = model.generate_content(final_prompt) if not result.candidates: return None, "❌ Gagal: tiada kandidat dihasilkan" image_bytes = result.candidates[0].content.parts[0].inline_data.data fname = "output_img.png" with open(fname, "wb") as f: f.write(base64.b64decode(image_bytes)) return fname, "✅ Gambar berjaya dihasilkan!" except Exception as e: return None, f"❌ Error: {str(e)}" # ========== SHORT VIDEO ========== def text_to_video(api_key, prompt, image_file, duration, aspect_ratio, resolution): try: set_api_key(api_key) model = genai.GenerativeModel("veo-3") # aspect ratio & res if aspect_ratio == "9:16": res = {"width": 720 if resolution == "720p" else 1080, "height": 1280 if resolution == "720p" else 1920} else: res = {"width": 1280 if resolution == "720p" else 1920, "height": 720 if resolution == "720p" else 1080} if image_file: final_prompt = {"text": prompt, "image": Image.open(image_file)} else: final_prompt = prompt result = model.generate_content({ "text": prompt, "config": { "duration_seconds": int(duration), "fps": 12, "video": {"width": res["width"], "height": res["height"]} } }) if not result.candidates: return None, "❌ Gagal: tiada kandidat video dihasilkan" video_bytes = result.candidates[0].content.parts[0].inline_data.data fname = "output_vid.mp4" with open(fname, "wb") as f: f.write(base64.b64decode(video_bytes)) return fname, "✅ Video berhasil dibuat!" except Exception as e: return None, f"❌ Error: {str(e)}" # ========== LONG VIDEO ========== def auto_segment_long_video(api_key, prompt, start_img, num_segments, duration_each, aspect_ratio, resolution): try: set_api_key(api_key) model = genai.GenerativeModel("veo-3") if aspect_ratio == "9:16": res = {"width": 720 if resolution == "720p" else 1080, "height": 1280 if resolution == "720p" else 1920} else: res = {"width": 1280 if resolution == "720p" else 1920, "height": 720 if resolution == "720p" else 1080} words = prompt.split() chunk_size = max(1, len(words) // num_segments) seg_prompts = [" ".join(words[i:i+chunk_size]) for i in range(0, len(words), chunk_size)][:num_segments] carry_image = Image.open(start_img) if start_img else None segment_files = [] for idx, text in enumerate(seg_prompts): if carry_image: final_prompt = {"text": text, "image": carry_image} else: final_prompt = text result = model.generate_content({ "text": text, "config": { "duration_seconds": int(duration_each), "fps": 12, "video": {"width": res["width"], "height": res["height"]} } }) if not result.candidates: return None, f"❌ Gagal buat segmen {idx}" video_bytes = result.candidates[0].content.parts[0].inline_data.data fname = f"seg_{idx}.mp4" with open(fname, "wb") as f: f.write(base64.b64decode(video_bytes)) segment_files.append(fname) cap = cv2.VideoCapture(fname) cap.set(cv2.CAP_PROP_POS_FRAMES, cap.get(cv2.CAP_PROP_FRAME_COUNT) - 1) ret, frame = cap.read() cap.release() if ret: framefile = f"carry_{idx}.jpg" cv2.imwrite(framefile, frame) carry_image = Image.open(framefile) # gabung semua segmen list_file = "segments.txt" with open(list_file, "w") as f: for seg in segment_files: f.write(f"file '{seg}'\n") final_out = "final_long.mp4" subprocess.run( ["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", list_file, "-c", "copy", final_out], check=True ) return final_out, "✅ Video panjang berhasil dibuat!" except Exception as e: return None, f"❌ Error: {str(e)}" # ========== UI ========== with gr.Blocks(css=""" body {background: linear-gradient(160deg,#0f0c29,#302b63,#24243e);} .gradio-container {color:white;} h1,h2,h3,h4,label {color:white !important;} button {background: linear-gradient(90deg,#6a11cb,#2575fc) !important; color:white !important;} """) as demo: gr.HTML("

🎥 Penjana Video VEO

") api_key = gr.Textbox(label="🔑 Masukkan Kunci API Gemini anda", type="password") with gr.Tabs(): with gr.Tab("🎬 Video Pendek"): prompt_vid = gr.Textbox(label="Prompt", placeholder="Tulis ide video...", lines=4) vid_file = gr.File(label="Imej Rujukan (Opsional)", file_types=[".jpg",".png"], type="filepath") duration = gr.Slider(3, 8, value=5, label="Tempoh (detik)") aspect_ratio = gr.Dropdown(choices=["16:9", "9:16"], value="16:9", label="Nisbah Aspek") resolution = gr.Dropdown(choices=["720p","1080p"], value="720p", label="Resolusi") btn_vid = gr.Button("Hasilkan Video Pendek") out_vid = gr.Video() msg_vid = gr.Label() btn_vid.click(fn=text_to_video, inputs=[api_key, prompt_vid, vid_file, duration, aspect_ratio, resolution], outputs=[out_vid, msg_vid]) with gr.Tab("🎞️ Video Panjang"): full_prompt = gr.Textbox(label="Prompt Narasi Panjang", placeholder="Tulis cerita panjang...", lines=6) start_img = gr.File(label="Imej Awal (Opsional)", file_types=[".jpg",".png"], type="filepath") num_segments = gr.Slider(1, 10, value=3, step=1, label="Jumlah Segmen") dur_each = gr.Slider(3, 8, value=5, step=1, label="Durasi/Segmen (detik)") aspect_ratio_long = gr.Dropdown(choices=["16:9", "9:16"], value="16:9", label="Nisbah Aspek") resolution_long = gr.Dropdown(choices=["720p","1080p"], value="720p", label="Resolusi") btn_long = gr.Button("Hasilkan Video Panjang") out_long = gr.Video() msg_long = gr.Label() btn_long.click(fn=auto_segment_long_video, inputs=[api_key, full_prompt, start_img, num_segments, dur_each, aspect_ratio_long, resolution_long], outputs=[out_long, msg_long]) with gr.Tab("🖼️ Imej"): prompt_img = gr.Textbox(label="Prompt", placeholder="Tulis ide gambar...", lines=4) img_file = gr.File(label="Imej Rujukan (Opsional)", file_types=[".jpg",".png"], type="filepath") resolution_img = gr.Dropdown(choices=["720p","1080p"], value="720p", label="Resolusi (dummy)") btn_img = gr.Button("Hasilkan Imej") out_img = gr.Image() msg_img = gr.Label() btn_img.click(fn=text_to_image, inputs=[api_key, prompt_img, img_file, resolution_img], outputs=[out_img, msg_img]) if __name__ == "__main__": demo.launch()