TDN-M commited on
Commit
3bb7349
·
verified ·
1 Parent(s): 2f7b37f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -17
app.py CHANGED
@@ -11,11 +11,12 @@ logging.basicConfig(level=logging.INFO)
11
  logger = logging.getLogger(__name__)
12
 
13
  # Cấu hình API TDNM
14
- VIDU_API_KEY = os.getenv("VIDU_API_KEY") # Giữ tên biến để tương thích với API
15
- TDNM_KEY = os.getenv("TDNM_KEY") # Khóa bí mật để xác thực người dùng
16
- VIDU_API_URL = "https://api.vidu.com" # URL API thực tế
17
  POLL_INTERVAL = 5 # Giây giữa các lần kiểm tra trạng thái
18
  TIMEOUT = 300 # Thời gian chờ tối đa để tạo video
 
19
 
20
  # Hàm kiểm tra TDNM_KEY
21
  def validate_tdn_key(user_key):
@@ -28,13 +29,13 @@ def validate_tdn_key(user_key):
28
  return True, "Khóa bí mật được xác thực thành công."
29
 
30
  # Hàm kiểm tra yêu cầu hình ảnh
31
- def validate_image(image_path):
32
  if not image_path:
33
  return False, "Lỗi: Chưa cung cấp hình ảnh."
34
 
35
- # Kiểm tra kích thước tệp (<10MB)
36
- if os.path.getsize(image_path) > 10 * 1024 * 1024:
37
- return False, "Lỗi: Kích thước hình ảnh vượt quá 10MB."
38
 
39
  # Kiểm tra định dạng
40
  mime_type, _ = mimetypes.guess_type(image_path)
@@ -52,7 +53,7 @@ def validate_image(image_path):
52
  except Exception as e:
53
  return False, f"Lỗi khi kiểm tra hình ảnh: {str(e)}"
54
 
55
- # Hàm kiểm tra tỷ lệ mật độ điểm ảnh giữa hai hình ảnh
56
  def validate_pixel_density(start_image, end_image):
57
  try:
58
  start_img = Image.open(start_image)
@@ -67,12 +68,12 @@ def validate_pixel_density(start_image, end_image):
67
  return False, f"Lỗi khi kiểm tra mật độ điểm ảnh: {str(e)}"
68
 
69
  # Hàm tải hình ảnh lên TDNM
70
- def upload_image_to_vidu(image_path):
71
  if not VIDU_API_KEY:
72
  return None, "Lỗi: Khóa API TDNM chưa được cấu hình."
73
 
74
  # Kiểm tra hình ảnh
75
- valid, error_message = validate_image(image_path)
76
  if not valid:
77
  return None, error_message
78
 
@@ -131,7 +132,7 @@ def upload_image_to_vidu(image_path):
131
  return None, f"Lỗi khi hoàn tất tải lên: {str(e)}"
132
 
133
  # Hàm gọi API TDNM cho Start-End to Video
134
- def start_end_to_video(start_image, end_image, prompt, model="vidu2.0", resolution="720p", duration=4, movement_amplitude="auto", seed=None, user_key=None):
135
  # Kiểm tra TDNM_KEY
136
  valid_key, key_message = validate_tdn_key(user_key)
137
  if not valid_key:
@@ -166,7 +167,7 @@ def start_end_to_video(start_image, end_image, prompt, model="vidu2.0", resoluti
166
  }
167
 
168
  payload = {
169
- "model": model,
170
  "images": [start_uri, end_uri],
171
  "prompt": prompt or "",
172
  "duration": duration,
@@ -191,6 +192,59 @@ def start_end_to_video(start_image, end_image, prompt, model="vidu2.0", resoluti
191
  logger.error(f"Phản hồi API: {response.text}")
192
  return None, f"Lỗi: {str(e)} - {response.text}"
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  # Placeholder cho References to Video
195
  def references_to_video(reference_images, prompt, resolution="720p", duration=4, user_key=None):
196
  # Kiểm tra TDNM_KEY
@@ -241,10 +295,20 @@ def check_task_status(task_id):
241
  return None, f"Lỗi: Hết thời gian tạo video. ID tác vụ: {task_id}"
242
 
243
  # Hàm giao diện Gradio cho Start-End to Video
244
- def gradio_start_end_to_video(start_image, end_image, prompt, model, resolution, duration, movement_amplitude, seed, user_key):
245
  if not start_image or not end_image:
246
  return None, "Lỗi: Cần cung cấp cả hai hình ảnh đầu và cuối."
247
- task_id, message = start_end_to_video(start_image, end_image, prompt, model, resolution, duration, movement_amplitude, seed, user_key)
 
 
 
 
 
 
 
 
 
 
248
  if not task_id:
249
  return None, message
250
  video_url, status_message = check_task_status(task_id)
@@ -268,7 +332,7 @@ with gr.Blocks(title="Trình Tạo Video TDNM") as demo:
268
  gr.Markdown("# Trình Tạo Video TDNM")
269
  gr.Markdown("Tạo video với TDNM. Vui lòng nhập khóa bí mật (TDNM_KEY) để sử dụng ứng dụng.")
270
 
271
- # Trường nhập khóa bí mật (áp dụng cho cả hai tab)
272
  user_key = gr.Textbox(label="Khóa Bí Mật (TDNM_KEY)", type="password", placeholder="Nhập khóa bí mật của bạn")
273
 
274
  # Tab cho Start-End to Video
@@ -277,7 +341,6 @@ with gr.Blocks(title="Trình Tạo Video TDNM") as demo:
277
  start_image = gr.Image(type="filepath", label="Hình Ảnh Đầu")
278
  end_image = gr.Image(type="filepath", label="Hình Ảnh Cuối")
279
  prompt_se = gr.Textbox(label="Mô Tả Văn Bản (Tùy Chọn)", placeholder="Ví dụ: 'Chuyển đổi mượt mà từ khung xe thành xe hoàn chỉnh.'")
280
- model_se = gr.Dropdown(choices=["vidu2.0", "vidu1.5"], label="Mô Hình", value="vidu2.0")
281
  resolution_se = gr.Dropdown(choices=["360p", "720p", "1080p"], label="Độ Phân Giải", value="720p")
282
  duration_se = gr.Dropdown(choices=[4, 8], label="Thời Lượng (giây)", value=4)
283
  movement_amplitude_se = gr.Dropdown(choices=["auto", "small", "medium", "large"], label="Biên Độ Chuyển Động", value="auto")
@@ -288,10 +351,29 @@ with gr.Blocks(title="Trình Tạo Video TDNM") as demo:
288
 
289
  se_button.click(
290
  fn=gradio_start_end_to_video,
291
- inputs=[start_image, end_image, prompt_se, model_se, resolution_se, duration_se, movement_amplitude_se, seed_se, user_key],
292
  outputs=[se_video_output, se_message]
293
  )
294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  # Tab cho References to Video (Placeholder)
296
  with gr.Tab("Video Từ Hình Ảnh Tham Chiếu"):
297
  gr.Markdown("Tải lên 1–3 hình ảnh tham chiếu và mô tả văn bản để tạo video. (Chưa được triển khai.)")
 
11
  logger = logging.getLogger(__name__)
12
 
13
  # Cấu hình API TDNM
14
+ VIDU_API_KEY = os.getenv("VIDU_API_KEY")
15
+ TDNM_KEY = os.getenv("TDNM_KEY")
16
+ VIDU_API_URL = "https://api.vidu.com"
17
  POLL_INTERVAL = 5 # Giây giữa các lần kiểm tra trạng thái
18
  TIMEOUT = 300 # Thời gian chờ tối đa để tạo video
19
+ DEFAULT_MODEL = "vidu2.0" # Mô hình mặc định
20
 
21
  # Hàm kiểm tra TDNM_KEY
22
  def validate_tdn_key(user_key):
 
29
  return True, "Khóa bí mật được xác thực thành công."
30
 
31
  # Hàm kiểm tra yêu cầu hình ảnh
32
+ def validate_image(image_path, max_size_mb=10):
33
  if not image_path:
34
  return False, "Lỗi: Chưa cung cấp hình ảnh."
35
 
36
+ # Kiểm tra kích thước tệp
37
+ if os.path.getsize(image_path) > max_size_mb * 1024 * 1024:
38
+ return False, f"Lỗi: Kích thước hình ảnh vượt quá {max_size_mb}MB."
39
 
40
  # Kiểm tra định dạng
41
  mime_type, _ = mimetypes.guess_type(image_path)
 
53
  except Exception as e:
54
  return False, f"Lỗi khi kiểm tra hình ảnh: {str(e)}"
55
 
56
+ # Hàm kiểm tra tỷ lệ mật độ điểm ảnh (cho start-end)
57
  def validate_pixel_density(start_image, end_image):
58
  try:
59
  start_img = Image.open(start_image)
 
68
  return False, f"Lỗi khi kiểm tra mật độ điểm ảnh: {str(e)}"
69
 
70
  # Hàm tải hình ảnh lên TDNM
71
+ def upload_image_to_vidu(image_path, max_size_mb=10):
72
  if not VIDU_API_KEY:
73
  return None, "Lỗi: Khóa API TDNM chưa được cấu hình."
74
 
75
  # Kiểm tra hình ảnh
76
+ valid, error_message = validate_image(image_path, max_size_mb)
77
  if not valid:
78
  return None, error_message
79
 
 
132
  return None, f"Lỗi khi hoàn tất tải lên: {str(e)}"
133
 
134
  # Hàm gọi API TDNM cho Start-End to Video
135
+ def start_end_to_video(start_image, end_image, prompt, resolution="720p", duration=4, movement_amplitude="auto", seed=None, user_key=None):
136
  # Kiểm tra TDNM_KEY
137
  valid_key, key_message = validate_tdn_key(user_key)
138
  if not valid_key:
 
167
  }
168
 
169
  payload = {
170
+ "model": DEFAULT_MODEL,
171
  "images": [start_uri, end_uri],
172
  "prompt": prompt or "",
173
  "duration": duration,
 
192
  logger.error(f"Phản hồi API: {response.text}")
193
  return None, f"Lỗi: {str(e)} - {response.text}"
194
 
195
+ # Hàm gọi API TDNM cho Img to Video
196
+ def img_to_video(image, prompt, resolution="720p", duration=4, movement_amplitude="auto", seed=None, user_key=None):
197
+ # Kiểm tra TDNM_KEY
198
+ valid_key, key_message = validate_tdn_key(user_key)
199
+ if not valid_key:
200
+ return None, key_message
201
+
202
+ if not VIDU_API_KEY:
203
+ return None, "Lỗi: Khóa API TDNM chưa được cấu hình."
204
+
205
+ if not image:
206
+ return None, "Lỗi: Cần cung cấp một hình ảnh."
207
+
208
+ if prompt and len(prompt) > 1500:
209
+ return None, "Lỗi: Mô tả văn bản không được vượt quá 1500 ký tự."
210
+
211
+ # Tải hình ảnh lên TDNM (giới hạn 50MB cho img2video)
212
+ image_uri, image_message = upload_image_to_vidu(image, max_size_mb=50)
213
+ if not image_uri:
214
+ return None, image_message
215
+
216
+ url = f"{VIDU_API_URL}/ent/v2/img2video"
217
+ headers = {
218
+ "Authorization": f"Token {VIDU_API_KEY}",
219
+ "Content-Type": "application/json"
220
+ }
221
+
222
+ payload = {
223
+ "model": DEFAULT_MODEL,
224
+ "images": [image_uri],
225
+ "prompt": prompt or "",
226
+ "duration": duration,
227
+ "resolution": resolution,
228
+ "movement_amplitude": movement_amplitude
229
+ }
230
+ if seed is not None:
231
+ payload["seed"] = seed
232
+
233
+ try:
234
+ logger.info(f"Gửi yêu cầu đến API TDNM Img to Video: {payload}")
235
+ response = requests.post(url, json=payload, headers=headers)
236
+ response.raise_for_status()
237
+ result = response.json()
238
+ task_id = result.get("task_id")
239
+ if not task_id:
240
+ return None, "Lỗi: Không nhận được ID tác vụ."
241
+ return task_id, f"Tác vụ được tạo thành công. ID tác vụ: {task_id}"
242
+ except requests.exceptions.RequestException as e:
243
+ logger.error(f"Lỗi API: {str(e)}")
244
+ if response.text:
245
+ logger.error(f"Phản hồi API: {response.text}")
246
+ return None, f"Lỗi: {str(e)} - {response.text}"
247
+
248
  # Placeholder cho References to Video
249
  def references_to_video(reference_images, prompt, resolution="720p", duration=4, user_key=None):
250
  # Kiểm tra TDNM_KEY
 
295
  return None, f"Lỗi: Hết thời gian tạo video. ID tác vụ: {task_id}"
296
 
297
  # Hàm giao diện Gradio cho Start-End to Video
298
+ def gradio_start_end_to_video(start_image, end_image, prompt, resolution, duration, movement_amplitude, seed, user_key):
299
  if not start_image or not end_image:
300
  return None, "Lỗi: Cần cung cấp cả hai hình ảnh đầu và cuối."
301
+ task_id, message = start_end_to_video(start_image, end_image, prompt, resolution, duration, movement_amplitude, seed, user_key)
302
+ if not task_id:
303
+ return None, message
304
+ video_url, status_message = check_task_status(task_id)
305
+ return video_url, status_message
306
+
307
+ # Hàm giao diện Gradio cho Img to Video
308
+ def gradio_img_to_video(image, prompt, resolution, duration, movement_amplitude, seed, user_key):
309
+ if not image:
310
+ return None, "Lỗi: Cần cung cấp một hình ảnh."
311
+ task_id, message = img_to_video(image, prompt, resolution, duration, movement_amplitude, seed, user_key)
312
  if not task_id:
313
  return None, message
314
  video_url, status_message = check_task_status(task_id)
 
332
  gr.Markdown("# Trình Tạo Video TDNM")
333
  gr.Markdown("Tạo video với TDNM. Vui lòng nhập khóa bí mật (TDNM_KEY) để sử dụng ứng dụng.")
334
 
335
+ # Trường nhập khóa bí mật (áp dụng cho tất cả các tab)
336
  user_key = gr.Textbox(label="Khóa Bí Mật (TDNM_KEY)", type="password", placeholder="Nhập khóa bí mật của bạn")
337
 
338
  # Tab cho Start-End to Video
 
341
  start_image = gr.Image(type="filepath", label="Hình Ảnh Đầu")
342
  end_image = gr.Image(type="filepath", label="Hình Ảnh Cuối")
343
  prompt_se = gr.Textbox(label="Mô Tả Văn Bản (Tùy Chọn)", placeholder="Ví dụ: 'Chuyển đổi mượt mà từ khung xe thành xe hoàn chỉnh.'")
 
344
  resolution_se = gr.Dropdown(choices=["360p", "720p", "1080p"], label="Độ Phân Giải", value="720p")
345
  duration_se = gr.Dropdown(choices=[4, 8], label="Thời Lượng (giây)", value=4)
346
  movement_amplitude_se = gr.Dropdown(choices=["auto", "small", "medium", "large"], label="Biên Độ Chuyển Động", value="auto")
 
351
 
352
  se_button.click(
353
  fn=gradio_start_end_to_video,
354
+ inputs=[start_image, end_image, prompt_se, resolution_se, duration_se, movement_amplitude_se, seed_se, user_key],
355
  outputs=[se_video_output, se_message]
356
  )
357
 
358
+ # Tab cho Img to Video
359
+ with gr.Tab("Video Từ Một Ảnh"):
360
+ gr.Markdown("Tải lên một hình ảnh và mô tả văn bản để tạo video. Hình ảnh phải là PNG, WebP, JPEG hoặc JPG, kích thước dưới 50MB, tỷ lệ khung hình từ 1:4 đến 4:1.")
361
+ image_i2v = gr.Image(type="filepath", label="Hình Ảnh")
362
+ prompt_i2v = gr.Textbox(label="Mô Tả Văn Bản (Tùy Chọn)", placeholder="Ví dụ: 'Phi hành gia vẫy tay và camera di chuyển lên.'")
363
+ resolution_i2v = gr.Dropdown(choices=["360p", "720p", "1080p"], label="Độ Phân Giải", value="720p")
364
+ duration_i2v = gr.Dropdown(choices=[4, 8], label="Thời Lượng (giây)", value=4)
365
+ movement_amplitude_i2v = gr.Dropdown(choices=["auto", "small", "medium", "large"], label="Biên Độ Chuyển Động", value="auto")
366
+ seed_i2v = gr.Number(label="Hạt Giống (Tùy Chọn)", value=None, precision=0)
367
+ i2v_button = gr.Button("Tạo Video")
368
+ i2v_video_output = gr.Video(label="Video Được Tạo")
369
+ i2v_message = gr.Textbox(label="Trạng Thái")
370
+
371
+ i2v_button.click(
372
+ fn=gradio_img_to_video,
373
+ inputs=[image_i2v, prompt_i2v, resolution_i2v, duration_i2v, movement_amplitude_i2v, seed_i2v, user_key],
374
+ outputs=[i2v_video_output, i2v_message]
375
+ )
376
+
377
  # Tab cho References to Video (Placeholder)
378
  with gr.Tab("Video Từ Hình Ảnh Tham Chiếu"):
379
  gr.Markdown("Tải lên 1–3 hình ảnh tham chiếu và mô tả văn bản để tạo video. (Chưa được triển khai.)")