hivecorp commited on
Commit
e6fc085
·
verified ·
1 Parent(s): ac5220b

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +44 -100
main.py CHANGED
@@ -1,10 +1,5 @@
1
- import os
2
- import uuid
3
- import requests
4
- from typing import List, Optional
5
- from fastapi import FastAPI
6
- from fastapi.staticfiles import StaticFiles
7
- from pydantic import BaseModel
8
  from moviepy.editor import (
9
  VideoFileClip,
10
  ImageClip,
@@ -13,112 +8,61 @@ from moviepy.editor import (
13
  CompositeVideoClip,
14
  ColorClip
15
  )
16
-
 
17
 
18
  app = FastAPI()
19
- os.makedirs("/app/output", exist_ok=True)
20
 
21
 
22
- # JSON Schema Models
23
- class Position(BaseModel):
24
- x: int
25
- y: int
26
 
27
 
28
- class Track(BaseModel):
29
- type: str # video, image, text, audio
30
- src: Optional[str] = None
31
- value: Optional[str] = None # For text
32
- start: float
33
- duration: Optional[float] = None
34
- position: Optional[Position] = None
35
- scale: Optional[float] = 1.0
36
- color: Optional[str] = "white"
37
- size: Optional[int] = 50
38
- font: Optional[str] = "Arial"
39
 
 
 
40
 
41
- class Canvas(BaseModel):
42
- width: int
43
- height: int
44
- duration: float
45
 
 
 
46
 
47
- class VideoInstruction(BaseModel):
48
- canvas: Canvas
49
- tracks: List[Track]
50
 
 
51
 
52
- # Serve generated videos via static file mount
53
- app.mount("/videos", StaticFiles(directory="output"), name="videos")
54
 
 
 
 
 
 
55
 
56
- # Utility to download assets
57
- def download_file(url, save_dir):
58
- filename = url.split("/")[-1].split("?")[0]
59
- path = os.path.join(save_dir, filename)
60
- with open(path, "wb") as f:
61
- f.write(requests.get(url).content)
62
- return path
63
 
 
 
64
 
65
- @app.post("/generate")
66
- def generate_video(job: VideoInstruction):
67
- job_id = str(uuid.uuid4())
68
- temp_dir = f"/tmp/{job_id}/"
69
- os.makedirs(temp_dir, exist_ok=True)
70
-
71
- clips = []
72
- audio_clip = None
73
-
74
- # Create solid background to match canvas size/duration
75
- bg_clip = ColorClip(size=(job.canvas.width, job.canvas.height), color=(0, 0, 0)).set_duration(job.canvas.duration)
76
- clips.append(bg_clip)
77
-
78
- for track in job.tracks:
79
- if track.type in ["video", "image", "audio"] and track.src:
80
- local_path = download_file(track.src, temp_dir)
81
-
82
- if track.type == "video":
83
- clip = VideoFileClip(local_path).set_start(track.start)
84
- if track.duration:
85
- clip = clip.subclip(0, track.duration)
86
- if track.position:
87
- clip = clip.set_position((track.position.x, track.position.y))
88
- if track.scale:
89
- clip = clip.resize(track.scale)
90
- clips.append(clip)
91
-
92
- elif track.type == "image":
93
- clip = ImageClip(local_path).set_start(track.start)
94
- duration = track.duration or job.canvas.duration - track.start
95
- clip = clip.set_duration(duration)
96
- if track.position:
97
- clip = clip.set_position((track.position.x, track.position.y))
98
- if track.scale:
99
- clip = clip.resize(track.scale)
100
- clips.append(clip)
101
-
102
- elif track.type == "text":
103
- clip = TextClip(
104
- track.value,
105
- fontsize=track.size,
106
- color=track.color,
107
- font=track.font
108
- ).set_start(track.start).set_duration(track.duration or 5)
109
- if track.position:
110
- clip = clip.set_position((track.position.x, track.position.y))
111
- clips.append(clip)
112
-
113
- elif track.type == "audio":
114
- audio_clip = AudioFileClip(local_path)
115
-
116
- final_clip = CompositeVideoClip(clips, size=(job.canvas.width, job.canvas.height)).set_duration(job.canvas.duration)
117
-
118
- if audio_clip:
119
- final_clip = final_clip.set_audio(audio_clip)
120
-
121
- output_file = f"/app/output/{job_id}.mp4"
122
- final_clip.write_videofile(output_file, fps=30, codec="libx264")
123
-
124
- return {"video_url": f"/videos/{job_id}.mp4"}
 
1
+ from fastapi import FastAPI, UploadFile, File
2
+ from fastapi.responses import FileResponse
 
 
 
 
 
3
  from moviepy.editor import (
4
  VideoFileClip,
5
  ImageClip,
 
8
  CompositeVideoClip,
9
  ColorClip
10
  )
11
+ import os
12
+ import uuid
13
 
14
  app = FastAPI()
 
15
 
16
 
17
+ @app.get("/")
18
+ async def root():
19
+ return {"message": "FastAPI with MoviePy is running."}
 
20
 
21
 
22
+ @app.post("/generate")
23
+ async def generate_video():
24
+ # Output video path
25
+ output_path = f"/app/generated_{uuid.uuid4().hex[:6]}.mp4"
 
 
 
 
 
 
 
26
 
27
+ # Create a colored background clip
28
+ bg_clip = ColorClip(size=(1280, 720), color=(10, 10, 10), duration=5)
29
 
30
+ # Create a text clip
31
+ txt_clip = TextClip("This is MoviePy via FastAPI", fontsize=70, color='white', font="DejaVu-Serif")
32
+ txt_clip = txt_clip.set_duration(5)
33
+ txt_clip = txt_clip.set_position(("center", "center"))
34
 
35
+ # Composite the video
36
+ final_clip = CompositeVideoClip([bg_clip, txt_clip])
37
 
38
+ # Write video to file
39
+ final_clip.write_videofile(output_path, fps=24, codec="libx264")
 
40
 
41
+ return FileResponse(output_path, media_type="video/mp4", filename=os.path.basename(output_path))
42
 
 
 
43
 
44
+ @app.post("/combine")
45
+ async def combine_video_audio(video_file: UploadFile = File(...), audio_file: UploadFile = File(...)):
46
+ video_path = f"/app/temp_video_{uuid.uuid4().hex[:6]}.mp4"
47
+ audio_path = f"/app/temp_audio_{uuid.uuid4().hex[:6]}.mp3"
48
+ output_path = f"/app/output_{uuid.uuid4().hex[:6]}.mp4"
49
 
50
+ # Save the uploaded files
51
+ with open(video_path, "wb") as f:
52
+ f.write(await video_file.read())
 
 
 
 
53
 
54
+ with open(audio_path, "wb") as f:
55
+ f.write(await audio_file.read())
56
 
57
+ # Process with MoviePy
58
+ videoclip = VideoFileClip(video_path)
59
+ audioclip = AudioFileClip(audio_path)
60
+ videoclip = videoclip.set_audio(audioclip)
61
+
62
+ videoclip.write_videofile(output_path, codec="libx264", fps=24)
63
+
64
+ # Clean temp files
65
+ os.remove(video_path)
66
+ os.remove(audio_path)
67
+
68
+ return FileResponse(output_path, media_type="video/mp4", filename=os.path.basename(output_path))