Aliashraf commited on
Commit
2a2eddb
·
verified ·
1 Parent(s): 3e10e3a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -0
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import FileResponse
3
+ from gtts import gTTS
4
+ import cv2
5
+ import numpy as np
6
+ from PIL import Image, ImageDraw, ImageFont
7
+ import os
8
+
9
+ app = FastAPI()
10
+
11
+ # Function to split the script into smaller chunks
12
+ def split_script(script: str, max_words: int = 50):
13
+ words = script.split()
14
+ chunks = [" ".join(words[i:i + max_words]) for i in range(0, len(words), max_words)]
15
+ return chunks
16
+
17
+ # Function to create a video segment from a script chunk
18
+ def create_video_segment(script_chunk: str, background_color: str, text_color: str, font_size: int):
19
+ try:
20
+ # Step 1: Convert script chunk to audio using gTTS
21
+ tts = gTTS(script_chunk)
22
+ audio_file = "output_audio.mp3"
23
+ tts.save(audio_file)
24
+
25
+ # Step 2: Create a blank image with text
26
+ width, height = 1280, 720 # HD resolution
27
+ background_color_rgb = tuple(int(background_color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4))
28
+ text_color_rgb = tuple(int(text_color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4))
29
+
30
+ # Create a blank image with the background color
31
+ image = Image.new("RGB", (width, height), background_color_rgb)
32
+ draw = ImageDraw.Draw(image)
33
+
34
+ # Load a font (you can use a default font or provide a .ttf file)
35
+ try:
36
+ font = ImageFont.truetype("arial.ttf", font_size)
37
+ except IOError:
38
+ font = ImageFont.load_default()
39
+
40
+ # Add text to the image
41
+ text_width, text_height = draw.textsize(script_chunk, font=font)
42
+ text_x = (width - text_width) // 2
43
+ text_y = (height - text_height) // 2
44
+ draw.text((text_x, text_y), script_chunk, font=font, fill=text_color_rgb)
45
+
46
+ # Convert the image to a numpy array for OpenCV
47
+ frame = np.array(image)
48
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
49
+
50
+ # Step 3: Create a video segment with the image and audio
51
+ video_segment_file = f"video_segment_{len(os.listdir())}.mp4"
52
+ fps = 24
53
+ fourcc = cv2.VideoWriter_fourcc(*"mp4v")
54
+ video_writer = cv2.VideoWriter(video_segment_file, fourcc, fps, (width, height))
55
+
56
+ # Calculate the number of frames based on audio duration
57
+ audio_duration = len(script_chunk.split()) * 0.5 # Approximate duration (adjust as needed)
58
+ num_frames = int(audio_duration * fps)
59
+
60
+ # Write the frames to the video
61
+ for _ in range(num_frames):
62
+ video_writer.write(frame)
63
+
64
+ # Release the video writer
65
+ video_writer.release()
66
+
67
+ # Step 4: Add audio to the video segment using ffmpeg (if available)
68
+ if os.path.exists(audio_file):
69
+ final_video_segment_file = f"final_{video_segment_file}"
70
+ os.system(f"ffmpeg -i {video_segment_file} -i {audio_file} -c:v copy -c:a aac {final_video_segment_file}")
71
+ os.remove(video_segment_file)
72
+ os.remove(audio_file)
73
+ return final_video_segment_file
74
+ else:
75
+ return video_segment_file
76
+ except Exception as e:
77
+ raise HTTPException(status_code=500, detail=str(e))
78
+
79
+ # Function to combine video segments into a single video
80
+ def combine_video_segments(video_segment_files: list, output_file: str = "final_output_video.mp4"):
81
+ try:
82
+ with open("video_list.txt", "w") as f:
83
+ for segment in video_segment_files:
84
+ f.write(f"file '{segment}'\n")
85
+
86
+ # Combine video segments using ffmpeg
87
+ os.system(f"ffmpeg -f concat -safe 0 -i video_list.txt -c copy {output_file}")
88
+
89
+ # Clean up video segments
90
+ for segment in video_segment_files:
91
+ os.remove(segment)
92
+ os.remove("video_list.txt")
93
+
94
+ return output_file
95
+ except Exception as e:
96
+ raise HTTPException(status_code=500, detail=str(e))
97
+
98
+ # API Endpoint to generate video
99
+ @app.post("/generate-video")
100
+ async def generate_video(script: str, background_color: str = "#000000", text_color: str = "#FFFFFF", font_size: int = 50):
101
+ if not script:
102
+ raise HTTPException(status_code=400, detail="Script cannot be empty")
103
+
104
+ try:
105
+ # Step 1: Split the script into smaller chunks
106
+ script_chunks = split_script(script)
107
+
108
+ # Step 2: Generate video segments for each chunk
109
+ video_segment_files = []
110
+ for chunk in script_chunks:
111
+ video_segment = create_video_segment(chunk, background_color, text_color, font_size)
112
+ video_segment_files.append(video_segment)
113
+
114
+ # Step 3: Combine video segments into a single video
115
+ final_video_file = combine_video_segments(video_segment_files)
116
+
117
+ # Step 4: Return the final video file
118
+ if not os.path.exists(final_video_file):
119
+ raise HTTPException(status_code=500, detail="Failed to generate video")
120
+
121
+ return FileResponse(final_video_file, media_type="video/mp4", filename="generated_video.mp4")
122
+ except Exception as e:
123
+ raise HTTPException(status_code=500, detail=str(e))
124
+
125
+ # Run the application
126
+ if __name__ == "__main__":
127
+ import uvicorn
128
+ uvicorn.run(app, host="0.0.0.0", port=8000)