File size: 4,708 Bytes
ff06804
 
ed0822f
b1f9ba3
9758ce3
 
169c6dc
9758ce3
1f02e8c
9758ce3
10a3486
 
ff06804
aebdc5b
9758ce3
ff06804
9758ce3
10a3486
9758ce3
1f02e8c
 
 
 
 
 
 
9758ce3
 
 
 
 
 
 
 
10a3486
169c6dc
10a3486
 
1f02e8c
10a3486
 
 
 
1f02e8c
 
 
10a3486
 
4bb12b5
1f02e8c
4bb12b5
 
1f02e8c
4bb12b5
169c6dc
10a3486
e7e354e
ebdb1c7
ec9f220
9758ce3
 
 
 
 
 
169c6dc
 
4df7670
 
 
 
169c6dc
 
9758ce3
 
169c6dc
ff06804
9758ce3
 
 
 
e7e354e
9758ce3
 
e7e354e
ed0822f
9758ce3
ed0822f
e7e354e
9758ce3
169c6dc
e7e354e
ff06804
 
9758ce3
e7e354e
1f02e8c
 
 
 
 
169c6dc
 
b1f9ba3
ec9f220
 
e7e354e
169c6dc
 
9758ce3
 
ee57331
9758ce3
 
e7e354e
9758ce3
ff06804
e7e354e
ff06804
 
 
e7e354e
ff06804
 
9758ce3
169c6dc
 
9758ce3
169c6dc
 
 
 
 
 
e7e354e
9758ce3
169c6dc
9758ce3
169c6dc
 
e7e354e
9758ce3
ff06804
 
 
 
 
 
 
 
 
 
 
 
1f02e8c
ec9f220
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import sys
import os
import re
import time
import textwrap
import numpy as np
import requests
from PIL import Image, ImageDraw, ImageFont
from moviepy.editor import ImageClip, concatenate_videoclips, AudioFileClip
from io import BytesIO
import asyncio
import edge_tts
import upload

WIDTH, HEIGHT = 1080, 1920
FPS = 30
DURATION_PER_LINE = 4
PEXELS_API_KEY = os.environ.get('PEXELS_API_KEY', '')

KEYWORDS = [
    "india city", "india technology", "india traffic",
    "india government", "india future", "india electric car",
    "india startup", "india innovation", "india growth",
    "india 2026", "india street", "india economy"
]

def clean_script(text):
    text = re.sub(r'\*\*.*?\*\*', '', text)
    text = re.sub(r'\(.*?\)', '', text)
    text = re.sub(r'Host:|Expert:|Narrator:|Title:|Script:', '', text)
    text = re.sub(r'\[.*?\]', '', text)
    text = re.sub(r'#\w+', '', text)
    return text.strip()

def get_pexels_image(keyword):
    try:
        headers = {'Authorization': PEXELS_API_KEY}
        r = requests.get(
            f'https://api.pexels.com/v1/search?query={keyword}&per_page=10&orientation=portrait',
            headers=headers, timeout=15
        )
        data = r.json()
        if data.get('photos'):
            import random
            photo = random.choice(data['photos'])
            photo_url = photo['src']['portrait']
            img_response = requests.get(photo_url, timeout=15)
            img = Image.open(BytesIO(img_response.content)).convert('RGB')
            img = img.resize((WIDTH, HEIGHT))
            print(f"Pexels image fetched for '{keyword}' ✅")
            return img
        else:
            print(f"No photos for: {keyword}")
            return None
    except Exception as e:
        print(f"Pexels error: {e}")
        return None

def make_frame(bg_image=None):
    if bg_image:
        img = bg_image.copy()
    else:
        img = Image.new('RGB', (WIDTH, HEIGHT), color=(15, 15, 25))
    return np.array(img)

def generate_tts(text, output_path):
    try:
        async def speak():
            communicate = edge_tts.Communicate(text, voice="en-IN-NeerjaNeural")
            await communicate.save(output_path)
        asyncio.run(speak())
        return True
    except Exception as e:
        print(f"TTS error: {e}")
        return False

def generate_video(script, title, description):
    print("Starting cinematic video generation...")
    print(f"Script received: {script[:100]}")

    cleaned = clean_script(script)

    sentences = re.split(r'[.!?\n]', cleaned)
    sentences = [s.strip() for s in sentences if len(s.strip()) > 10]

    if not sentences:
        words = cleaned.split()
        sentences = [' '.join(words[i:i+8]) for i in range(0, len(words), 8)]

    sentences = sentences[:10]
    print(f"Total clips: {len(sentences)}")

    clips = []
    for i, sentence in enumerate(sentences):
        print(f"Creating clip {i+1}/{len(sentences)}: {sentence[:40]}")

        # Different Pexels image for each clip
        keyword = KEYWORDS[i % len(KEYWORDS)]
        bg_image = get_pexels_image(keyword)

        # TTS audio
        audio_path = f'/app/audio_{i}.mp3'
        has_audio = generate_tts(sentence, audio_path)

        # Create frame - no text overlay
        frame = make_frame(bg_image)

        if has_audio and os.path.exists(audio_path):
            audio = AudioFileClip(audio_path)
            duration = max(audio.duration + 0.5, DURATION_PER_LINE)
            clip = ImageClip(frame, duration=duration)
            clip = clip.set_audio(audio)
        else:
            clip = ImageClip(frame, duration=DURATION_PER_LINE)

        clip = clip.fadein(0.5).fadeout(0.5)
        clips.append(clip)

    if not clips:
        print("No clips generated!")
        return False

    print("Combining clips...")
    final = concatenate_videoclips(clips, method="compose")
    output_path = '/app/video.mp4'
    print("Writing video...")
    final.write_videofile(
        output_path,
        fps=FPS,
        codec='libx264',
        audio_codec='aac',
        verbose=False,
        logger=None
    )

    for i in range(len(sentences)):
        try:
            os.remove(f'/app/audio_{i}.mp3')
        except:
            pass

    print("Cinematic video generated successfully!")
    return True

if __name__ == '__main__':
    script = sys.argv[1]
    title = sys.argv[2]
    description = sys.argv[3]
    success = generate_video(script, title, description)
    if success:
        print("Uploading to YouTube...")
        video_id = upload.upload_video(title, description)
        print(f"SUCCESS: https://youtube.com/shorts/{video_id}")
    else:
        print("Video generation failed!")