ginipick commited on
Commit
a5e046f
·
verified ·
1 Parent(s): ac825a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -109
app.py CHANGED
@@ -14,57 +14,57 @@ import requests
14
  from datetime import datetime
15
  import tempfile
16
 
17
- # API 토큰 설정
18
  api_token = os.getenv("RAPI_TOKEN")
19
  if api_token:
20
  os.environ["REPLICATE_API_TOKEN"] = api_token
21
 
22
- # 화면 비율 옵션
23
  ASPECT_RATIOS = {
24
- "16:9": "16:9 (YouTube, 일반 동영상)",
25
- "4:3": "4:3 (전통적인 TV 형식)",
26
- "1:1": "1:1 (Instagram 피드)",
27
- "3:4": "3:4 (Instagram 포트레이트)",
28
- "9:16": "9:16 (Instagram 릴스, TikTok)",
29
- "21:9": "21:9 (시네마틱 와이드)",
30
- "9:21": "9:21 (울트라 세로형)"
31
  }
32
 
33
  def update_prompt_placeholder(mode):
34
- """모드에 따라 프롬프트 플레이스홀더 업데이트"""
35
- if mode == "텍스트 to 비디오":
36
- return gr.update(placeholder="생성할 비디오를 설명해주세요.\n예: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn.")
37
  else:
38
- return gr.update(placeholder="이미지를 어떻게 움직이게 할지 설명해주세요.\n예: Camera slowly zooms in while clouds move across the sky. The subject's hair gently moves in the wind.")
39
 
40
  def update_image_input(mode):
41
- """모드에 따라 이미지 입력 표시/숨김"""
42
- if mode == "이미지 to 비디오":
43
  return gr.update(visible=True)
44
  else:
45
  return gr.update(visible=False)
46
 
47
  def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_input, progress=gr.Progress()):
48
- """비디오 생성 메인 함수"""
49
 
50
- # API 토큰 확인
51
  token = api_key_input or api_token
52
  if not token:
53
- return None, "❌ API 토큰이 필요합니다. 환경변수 RAPI_TOKEN 설정하거나 API 키를 입력하세요."
54
 
55
  os.environ["REPLICATE_API_TOKEN"] = token
56
 
57
- # 입력 검증
58
  if not prompt:
59
- return None, "❌ 프롬프트를 입력해주세요."
60
 
61
- if mode == "이미지 to 비디오" and image is None:
62
- return None, "❌ 이미지를 업로드해주세요."
63
 
64
  try:
65
- progress(0, desc="비디오 생성 준비 중...")
66
 
67
- # 입력 파라미터 설정
68
  input_params = {
69
  "prompt": prompt,
70
  "duration": 5,
@@ -73,210 +73,210 @@ def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_input, progr
73
  "seed": seed
74
  }
75
 
76
- # 이미지 to 비디오 모드
77
- if mode == "이미지 to 비디오" and image is not None:
78
- progress(0.1, desc="이미지 처리 중...")
79
 
80
- # PIL Image base64로 변환
81
- if isinstance(image, str): # 파일 경로인 경우
82
  with Image.open(image) as img:
83
  buffered = io.BytesIO()
84
  img.save(buffered, format="PNG")
85
  image_base64 = base64.b64encode(buffered.getvalue()).decode()
86
- else: # PIL Image 객체인 경우
87
  buffered = io.BytesIO()
88
  image.save(buffered, format="PNG")
89
  image_base64 = base64.b64encode(buffered.getvalue()).decode()
90
 
91
  input_params["image"] = f"data:image/png;base64,{image_base64}"
92
 
93
- progress(0.3, desc="Replicate API 호출 중...")
94
 
95
- # Replicate 실행
96
  output = replicate.run(
97
  "bytedance/seedance-1-lite",
98
  input=input_params
99
  )
100
 
101
- progress(0.7, desc="비디오 다운로드 중...")
102
 
103
- # 비디오 데이터 가져오기
104
  if hasattr(output, 'read'):
105
  video_data = output.read()
106
  else:
107
- # URL인 경우 다운로드
108
  response = requests.get(output)
109
  video_data = response.content
110
 
111
- # 임시 파일로 저장
112
  with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp_file:
113
  tmp_file.write(video_data)
114
  video_path = tmp_file.name
115
 
116
- # output.mp4로도 저장
117
  with open("output.mp4", "wb") as file:
118
  file.write(video_data)
119
 
120
- progress(1.0, desc="완료!")
121
 
122
- # 생성 정보
123
- info = f"""✅ 비디오가 성공적으로 생성되었습니다!
124
 
125
- 📊 생성 정보:
126
- - 모드: {mode}
127
- - 화면 비율: {aspect_ratio}
128
  - Seed: {seed}
129
- - 재생 시간: 5초
130
- - 해상도: 480p
131
- - 파일: output.mp4"""
132
 
133
  return video_path, info
134
 
135
  except Exception as e:
136
- error_msg = f"❌ 오류가 발생했습니다: {str(e)}"
137
  return None, error_msg
138
 
139
- # Gradio 인터페이스 생성
140
- with gr.Blocks(title="AI Video Generator", theme=gr.themes.Soft()) as app:
141
  gr.Markdown("""
142
- # 🎬 AI Video Generator
143
 
144
- **Replicate API**를 사용하여 텍스트나 이미지로부터 비디오를 생성합니다.
145
 
146
  [![Powered by Ginigen](https://img.shields.io/badge/Powered%20by-Replicate-blue)](https://ginigen.com/)
147
  """)
148
 
149
  with gr.Row():
150
  with gr.Column(scale=1):
151
- # API 설정
152
- with gr.Accordion("⚙️ API 설정", open=not bool(api_token)):
153
  if api_token:
154
- gr.Markdown("✅ API 토큰이 환경변수에서 로드되었습니다.")
155
  api_key_input = gr.Textbox(
156
- label="Replicate API Token (선택사항)",
157
  type="password",
158
- placeholder="환경변수를 덮어쓰려면 여기에 입력",
159
  value=""
160
  )
161
  else:
162
- gr.Markdown("⚠️ 환경변수 RAPI_TOKEN 설정되지 않았습니다.")
163
  api_key_input = gr.Textbox(
164
- label="Replicate API Token (필수)",
165
  type="password",
166
- placeholder="Replicate API 토큰을 입력하세요",
167
  value=""
168
  )
169
 
170
- # 생성 모드
171
  mode = gr.Radio(
172
- label="🎯 생성 모드",
173
- choices=["텍스트 to 비디오", "이미지 to 비디오"],
174
- value="텍스트 to 비디오"
175
  )
176
 
177
- # 이미지 업로드
178
  image_input = gr.Image(
179
- label="📷 이미지 업로드",
180
  type="pil",
181
  visible=False
182
  )
183
 
184
- # 화면 비율
185
  aspect_ratio = gr.Dropdown(
186
- label="📐 화면 비율",
187
  choices=list(ASPECT_RATIOS.keys()),
188
  value="16:9",
189
- info="SNS 플랫폼에 최적화된 비율을 선택하세요"
190
  )
191
 
192
- # 비율 설명 표시
193
- ratio_info = gr.Markdown(value=f"선택된 비율: {ASPECT_RATIOS['16:9']}")
194
 
195
- # Seed 설정
196
  seed = gr.Number(
197
- label="🎲 랜덤 시드",
198
  value=42,
199
  precision=0,
200
- info="동일한 시드값으로 동일한 결과를 재현할 있습니다"
201
  )
202
 
203
- # 고정 설정 표시
204
  gr.Markdown("""
205
- ### 📋 고정 설정
206
- - **재생 시간**: 5초
207
- - **해상도**: 480p
208
  """)
209
 
210
  with gr.Column(scale=2):
211
- # 프롬프트 입력
212
  prompt = gr.Textbox(
213
- label="✍️ 프롬프트",
214
  lines=5,
215
- placeholder="생성할 비디오를 설명해주세요.\n예: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn."
216
  )
217
 
218
- # 생성 버튼
219
- generate_btn = gr.Button("🎬 비디오 생성", variant="primary", size="lg")
220
 
221
- # 결과 표시
222
  with gr.Column():
223
  output_video = gr.Video(
224
- label="📹 생성된 비디오",
225
  autoplay=True
226
  )
227
  output_info = gr.Textbox(
228
- label="정보",
229
  lines=8,
230
  interactive=False
231
  )
232
 
233
- # 사용 방법
234
- with gr.Accordion("📖 사용 방법", open=False):
235
  gr.Markdown("""
236
- ### 설치 방법
237
 
238
- 1. **필요한 패키지 설치**:
239
  ```bash
240
  pip install gradio replicate pillow requests
241
  ```
242
 
243
- 2. **환경변수 설정** (선택사항):
244
  ```bash
245
  export RAPI_TOKEN="your-replicate-api-token"
246
  ```
247
 
248
- 3. **실행**:
249
  ```bash
250
  python app.py
251
  ```
252
 
253
- ### 기능 설명
254
 
255
- - **텍스트 to 비디오**: 텍스트 설명만으로 비디오를 생성합니다.
256
- - **이미지 to 비디오**: 업로드한 이미지를 움직이는 비디오로 변환합니다.
257
- - **화면 비율**: 다양한 SNS 플랫폼에 최적화된 비율을 선택할 있습니다.
258
- - **Seed 값**: 동일한 시드값으로 동일한 결과를 재현할 있습니다.
259
 
260
- ### 프롬프트 작성
261
 
262
- - 구체적이고 상세한 설명을 사용하세요
263
- - 카메라 움직임을 명시하세요 (예: zoom in, pan left, tracking shot)
264
- - 조명과 분위기를 설명하세요 (예: golden hour, dramatic lighting)
265
- - 움직임의 속도를 지정하세요 (예: slowly, rapidly, gently)
266
  """)
267
 
268
- # 예시
269
  gr.Examples(
270
  examples=[
271
- ["텍스트 to 비디오", "A serene lake at sunrise with mist rolling over the water. Camera slowly pans across the landscape as birds fly overhead.", None, "16:9", 42],
272
- ["텍스트 to 비디오", "Urban street scene at night with neon lights reflecting on wet pavement. People walking with umbrellas, camera tracking forward.", None, "9:16", 123],
273
- ["텍스트 to 비디오", "Close-up of a flower blooming in time-lapse, soft natural lighting, shallow depth of field.", None, "1:1", 789],
274
  ],
275
  inputs=[mode, prompt, image_input, aspect_ratio, seed],
276
- label="예시 프롬프트"
277
  )
278
 
279
- # 이벤트 핸들러
280
  mode.change(
281
  fn=update_prompt_placeholder,
282
  inputs=[mode],
@@ -290,7 +290,7 @@ with gr.Blocks(title="AI Video Generator", theme=gr.themes.Soft()) as app:
290
  )
291
 
292
  aspect_ratio.change(
293
- fn=lambda x: f"선택된 비율: {ASPECT_RATIOS[x]}",
294
  inputs=[aspect_ratio],
295
  outputs=[ratio_info]
296
  )
@@ -301,7 +301,7 @@ with gr.Blocks(title="AI Video Generator", theme=gr.themes.Soft()) as app:
301
  outputs=[output_video, output_info]
302
  )
303
 
304
- # 실행
305
  if __name__ == "__main__":
306
  app.launch(
307
  server_name="0.0.0.0",
 
14
  from datetime import datetime
15
  import tempfile
16
 
17
+ # API token setup
18
  api_token = os.getenv("RAPI_TOKEN")
19
  if api_token:
20
  os.environ["REPLICATE_API_TOKEN"] = api_token
21
 
22
+ # Aspect ratio options
23
  ASPECT_RATIOS = {
24
+ "16:9": "16:9 (YouTube, Standard Video)",
25
+ "4:3": "4:3 (Traditional TV Format)",
26
+ "1:1": "1:1 (Instagram Feed)",
27
+ "3:4": "3:4 (Instagram Portrait)",
28
+ "9:16": "9:16 (Instagram Reels, TikTok)",
29
+ "21:9": "21:9 (Cinematic Wide)",
30
+ "9:21": "9:21 (Ultra Vertical)"
31
  }
32
 
33
  def update_prompt_placeholder(mode):
34
+ """Update prompt placeholder based on mode"""
35
+ if mode == "Text to Video":
36
+ return gr.update(placeholder="Describe the video you want to create.\nExample: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn.")
37
  else:
38
+ return gr.update(placeholder="Describe how the image should move.\nExample: Camera slowly zooms in while clouds move across the sky. The subject's hair gently moves in the wind.")
39
 
40
  def update_image_input(mode):
41
+ """Show/hide image input based on mode"""
42
+ if mode == "Image to Video":
43
  return gr.update(visible=True)
44
  else:
45
  return gr.update(visible=False)
46
 
47
  def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_input, progress=gr.Progress()):
48
+ """Main video generation function"""
49
 
50
+ # API token check
51
  token = api_key_input or api_token
52
  if not token:
53
+ return None, "❌ API token required. Please set RAPI_TOKEN environment variable or enter your API key."
54
 
55
  os.environ["REPLICATE_API_TOKEN"] = token
56
 
57
+ # Input validation
58
  if not prompt:
59
+ return None, "❌ Please enter a prompt."
60
 
61
+ if mode == "Image to Video" and image is None:
62
+ return None, "❌ Please upload an image."
63
 
64
  try:
65
+ progress(0, desc="Preparing video generation...")
66
 
67
+ # Input parameters setup
68
  input_params = {
69
  "prompt": prompt,
70
  "duration": 5,
 
73
  "seed": seed
74
  }
75
 
76
+ # Image to video mode
77
+ if mode == "Image to Video" and image is not None:
78
+ progress(0.1, desc="Processing image...")
79
 
80
+ # Convert PIL Image to base64
81
+ if isinstance(image, str): # File path
82
  with Image.open(image) as img:
83
  buffered = io.BytesIO()
84
  img.save(buffered, format="PNG")
85
  image_base64 = base64.b64encode(buffered.getvalue()).decode()
86
+ else: # PIL Image object
87
  buffered = io.BytesIO()
88
  image.save(buffered, format="PNG")
89
  image_base64 = base64.b64encode(buffered.getvalue()).decode()
90
 
91
  input_params["image"] = f"data:image/png;base64,{image_base64}"
92
 
93
+ progress(0.3, desc="Calling Replicate API...")
94
 
95
+ # Run Replicate
96
  output = replicate.run(
97
  "bytedance/seedance-1-lite",
98
  input=input_params
99
  )
100
 
101
+ progress(0.7, desc="Downloading video...")
102
 
103
+ # Get video data
104
  if hasattr(output, 'read'):
105
  video_data = output.read()
106
  else:
107
+ # Download from URL
108
  response = requests.get(output)
109
  video_data = response.content
110
 
111
+ # Save to temporary file
112
  with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp_file:
113
  tmp_file.write(video_data)
114
  video_path = tmp_file.name
115
 
116
+ # Also save as output.mp4
117
  with open("output.mp4", "wb") as file:
118
  file.write(video_data)
119
 
120
+ progress(1.0, desc="Complete!")
121
 
122
+ # Generation info
123
+ info = f"""✅ Video generated successfully!
124
 
125
+ 📊 Generation Info:
126
+ - Mode: {mode}
127
+ - Aspect Ratio: {aspect_ratio}
128
  - Seed: {seed}
129
+ - Duration: 5 seconds
130
+ - Resolution: 480p
131
+ - File: output.mp4"""
132
 
133
  return video_path, info
134
 
135
  except Exception as e:
136
+ error_msg = f"❌ Error occurred: {str(e)}"
137
  return None, error_msg
138
 
139
+ # Gradio interface
140
+ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as app:
141
  gr.Markdown("""
142
+ # 🎬 Bytedance Seedance Video' Free
143
 
144
+ Generate videos from text or images using **Replicate API**.
145
 
146
  [![Powered by Ginigen](https://img.shields.io/badge/Powered%20by-Replicate-blue)](https://ginigen.com/)
147
  """)
148
 
149
  with gr.Row():
150
  with gr.Column(scale=1):
151
+ # API Settings
152
+ with gr.Accordion("⚙️ API Settings", open=not bool(api_token)):
153
  if api_token:
154
+ gr.Markdown("✅ API token loaded from environment variable.")
155
  api_key_input = gr.Textbox(
156
+ label="Replicate API Token (Optional)",
157
  type="password",
158
+ placeholder="Enter to override environment variable",
159
  value=""
160
  )
161
  else:
162
+ gr.Markdown("⚠️ RAPI_TOKEN environment variable not set.")
163
  api_key_input = gr.Textbox(
164
+ label="Replicate API Token (Required)",
165
  type="password",
166
+ placeholder="Enter your Replicate API token",
167
  value=""
168
  )
169
 
170
+ # Generation mode
171
  mode = gr.Radio(
172
+ label="🎯 Generation Mode",
173
+ choices=["Text to Video", "Image to Video"],
174
+ value="Text to Video"
175
  )
176
 
177
+ # Image upload
178
  image_input = gr.Image(
179
+ label="📷 Upload Image",
180
  type="pil",
181
  visible=False
182
  )
183
 
184
+ # Aspect ratio
185
  aspect_ratio = gr.Dropdown(
186
+ label="📐 Aspect Ratio",
187
  choices=list(ASPECT_RATIOS.keys()),
188
  value="16:9",
189
+ info="Choose ratio optimized for social media platforms"
190
  )
191
 
192
+ # Ratio description
193
+ ratio_info = gr.Markdown(value=f"Selected ratio: {ASPECT_RATIOS['16:9']}")
194
 
195
+ # Seed setting
196
  seed = gr.Number(
197
+ label="🎲 Random Seed",
198
  value=42,
199
  precision=0,
200
+ info="Use same seed value to reproduce same results"
201
  )
202
 
203
+ # Fixed settings display
204
  gr.Markdown("""
205
+ ### 📋 Fixed Settings
206
+ - **Duration**: 5 seconds
207
+ - **Resolution**: 480p
208
  """)
209
 
210
  with gr.Column(scale=2):
211
+ # Prompt input
212
  prompt = gr.Textbox(
213
+ label="✍️ Prompt",
214
  lines=5,
215
+ placeholder="Describe the video you want to create.\nExample: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn."
216
  )
217
 
218
+ # Generate button
219
+ generate_btn = gr.Button("🎬 Generate Video", variant="primary", size="lg")
220
 
221
+ # Results display
222
  with gr.Column():
223
  output_video = gr.Video(
224
+ label="📹 Generated Video",
225
  autoplay=True
226
  )
227
  output_info = gr.Textbox(
228
+ label="Information",
229
  lines=8,
230
  interactive=False
231
  )
232
 
233
+ # Usage instructions
234
+ with gr.Accordion("📖 How to Use", open=False):
235
  gr.Markdown("""
236
+ ### Installation
237
 
238
+ 1. **Install required packages**:
239
  ```bash
240
  pip install gradio replicate pillow requests
241
  ```
242
 
243
+ 2. **Set environment variable** (optional):
244
  ```bash
245
  export RAPI_TOKEN="your-replicate-api-token"
246
  ```
247
 
248
+ 3. **Run**:
249
  ```bash
250
  python app.py
251
  ```
252
 
253
+ ### Features
254
 
255
+ - **Text to Video**: Generate video from text description only
256
+ - **Image to Video**: Transform uploaded image into animated video
257
+ - **Aspect Ratios**: Choose ratios optimized for various social media platforms
258
+ - **Seed Value**: Use same seed to reproduce identical results
259
 
260
+ ### Prompt Writing Tips
261
 
262
+ - Use specific and detailed descriptions
263
+ - Specify camera movements (e.g., zoom in, pan left, tracking shot)
264
+ - Describe lighting and atmosphere (e.g., golden hour, dramatic lighting)
265
+ - Indicate movement speed (e.g., slowly, rapidly, gently)
266
  """)
267
 
268
+ # Examples
269
  gr.Examples(
270
  examples=[
271
+ ["Text to Video", "A serene lake at sunrise with mist rolling over the water. Camera slowly pans across the landscape as birds fly overhead.", None, "16:9", 42],
272
+ ["Text to Video", "Urban street scene at night with neon lights reflecting on wet pavement. People walking with umbrellas, camera tracking forward.", None, "9:16", 123],
273
+ ["Text to Video", "Close-up of a flower blooming in time-lapse, soft natural lighting, shallow depth of field.", None, "1:1", 789],
274
  ],
275
  inputs=[mode, prompt, image_input, aspect_ratio, seed],
276
+ label="Example Prompts"
277
  )
278
 
279
+ # Event handlers
280
  mode.change(
281
  fn=update_prompt_placeholder,
282
  inputs=[mode],
 
290
  )
291
 
292
  aspect_ratio.change(
293
+ fn=lambda x: f"Selected ratio: {ASPECT_RATIOS[x]}",
294
  inputs=[aspect_ratio],
295
  outputs=[ratio_info]
296
  )
 
301
  outputs=[output_video, output_info]
302
  )
303
 
304
+ # Run app
305
  if __name__ == "__main__":
306
  app.launch(
307
  server_name="0.0.0.0",