Update video generation to use elai.
This commit is contained in:
24
app.py
24
app.py
@@ -14,11 +14,11 @@ from helper.exercises import *
|
||||
from helper.file_helper import delete_files_older_than_one_day
|
||||
from helper.firebase_helper import *
|
||||
from helper.gpt_zero import GPTZero
|
||||
from helper.heygen_api import create_video, create_videos_and_save_to_db
|
||||
from helper.elai_api import create_video, create_videos_and_save_to_db
|
||||
from helper.openai_interface import *
|
||||
from helper.question_templates import *
|
||||
from helper.speech_to_text_helper import *
|
||||
from heygen.AvatarEnum import AvatarEnum
|
||||
from elai.AvatarEnum import AvatarEnum
|
||||
from modules import GPT
|
||||
from modules.training_content import TrainingContentService, TrainingContentKnowledgeBase
|
||||
from modules.upload_level import UploadLevelService
|
||||
@@ -984,7 +984,7 @@ def generate_video_1():
|
||||
try:
|
||||
data = request.get_json()
|
||||
sp1_questions = []
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).name)
|
||||
|
||||
request_id = str(uuid.uuid4())
|
||||
logging.info("POST - generate_video_1 - Received request to generate video 1. "
|
||||
@@ -992,13 +992,13 @@ def generate_video_1():
|
||||
request.get_json()))
|
||||
|
||||
id_to_name = {
|
||||
"5912afa7c77c47d3883af3d874047aaf": "MATTHEW",
|
||||
"9e58d96a383e4568a7f1e49df549e0e4": "VERA",
|
||||
"d2cdd9c0379a4d06ae2afb6e5039bd0c": "EDWARD",
|
||||
"045cb5dcd00042b3a1e4f3bc1c12176b": "TANYA",
|
||||
"1ae1e5396cc444bfad332155fdb7a934": "KAYLA",
|
||||
"0ee6aa7cc1084063a630ae514fccaa31": "JEROME",
|
||||
"5772cff935844516ad7eeff21f839e43": "TYLER",
|
||||
"VADIM_BUSINESS": "MATTHEW",
|
||||
"GIA_BUSINESS": "VERA",
|
||||
"ORHAN_BUSINESS": "EDWARD",
|
||||
"FLORA_BUSINESS": "TANYA",
|
||||
"SCARLETT_BUSINESS": "KAYLA",
|
||||
"ETHAN_BUSINESS": "JEROME",
|
||||
"PARKER_CASUAL": "TYLER",
|
||||
|
||||
}
|
||||
|
||||
@@ -1052,7 +1052,7 @@ def generate_video_1():
|
||||
def generate_video_2():
|
||||
try:
|
||||
data = request.get_json()
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).name)
|
||||
prompts = data.get("prompts", [])
|
||||
question = data.get("question")
|
||||
suffix = data.get("suffix", "")
|
||||
@@ -1109,7 +1109,7 @@ def generate_video_3():
|
||||
try:
|
||||
data = request.get_json()
|
||||
sp3_questions = []
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
|
||||
avatar = data.get("avatar", random.choice(list(AvatarEnum)).name)
|
||||
|
||||
request_id = str(uuid.uuid4())
|
||||
logging.info("POST - generate_video_3 - Received request to generate video 3. "
|
||||
|
||||
62
elai/AvatarEnum.py
Normal file
62
elai/AvatarEnum.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class AvatarEnum(Enum):
|
||||
# Works
|
||||
GIA_BUSINESS = {
|
||||
"avatar_code": "gia.business",
|
||||
"avatar_gender": "female",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/gia/business/gia_business.png",
|
||||
"avatar_canvas": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/gia/business/gia_business.png",
|
||||
"voice_id": "EXAVITQu4vr4xnSDxMaL",
|
||||
"voice_provider": "elevenlabs"
|
||||
}
|
||||
# Works
|
||||
VADIM_BUSINESS = {
|
||||
"avatar_code": "vadim.business",
|
||||
"avatar_gender": "male",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/vadim/business/vadim_business.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/vadim/business/vadim_business.png",
|
||||
"voice_id": "flq6f7yk4E4fJM5XTYuZ",
|
||||
"voice_provider": "elevenlabs"
|
||||
}
|
||||
ORHAN_BUSINESS = {
|
||||
"avatar_code": "orhan.business",
|
||||
"avatar_gender": "male",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/orhan/business/orhan.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/orhan/business/orhan.png",
|
||||
"voice_id": "en-US-AndrewMultilingualNeural",
|
||||
"voice_provider": "azure"
|
||||
}
|
||||
FLORA_BUSINESS = {
|
||||
"avatar_code": "flora.business",
|
||||
"avatar_gender": "female",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/flora/business/flora_business.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/flora/business/flora_business.png",
|
||||
"voice_id": "en-US-JaneNeural",
|
||||
"voice_provider": "azure"
|
||||
}
|
||||
SCARLETT_BUSINESS = {
|
||||
"avatar_code": "scarlett.business",
|
||||
"avatar_gender": "female",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/scarlett/business/scarlett_business.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/scarlett/business/scarlett_business.png",
|
||||
"voice_id": "en-US-NancyNeural",
|
||||
"voice_provider": "azure"
|
||||
}
|
||||
PARKER_CASUAL = {
|
||||
"avatar_code": "parker.casual",
|
||||
"avatar_gender": "male",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/parker/casual/parker_casual.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/parker/casual/parker_casual.png",
|
||||
"voice_id": "en-US-TonyNeural",
|
||||
"voice_provider": "azure"
|
||||
}
|
||||
ETHAN_BUSINESS = {
|
||||
"avatar_code": "ethan.business",
|
||||
"avatar_gender": "male",
|
||||
"avatar_url": "https://elai-avatars.s3.us-east-2.amazonaws.com/common/ethan/business/ethan_business_low.png",
|
||||
"avatar_canvas": "https://d3u63mhbhkevz8.cloudfront.net/common/ethan/business/ethan_business_low.png",
|
||||
"voice_id": "en-US-JasonNeural",
|
||||
"voice_provider": "azure"
|
||||
}
|
||||
1965
elai/avatars.json
Normal file
1965
elai/avatars.json
Normal file
File diff suppressed because it is too large
Load Diff
3386
elai/english_voices.json
Normal file
3386
elai/english_voices.json
Normal file
File diff suppressed because it is too large
Load Diff
26579
elai/voices.json
Normal file
26579
elai/voices.json
Normal file
File diff suppressed because it is too large
Load Diff
263
helper/elai_api.py
Normal file
263
helper/elai_api.py
Normal file
@@ -0,0 +1,263 @@
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
from logging import getLogger
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from helper.constants import *
|
||||
from helper.firebase_helper import upload_file_firebase_get_url, save_to_db_with_id
|
||||
from elai.AvatarEnum import AvatarEnum
|
||||
|
||||
load_dotenv()
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
# Get ELAI token
|
||||
TOKEN = os.getenv("ELAI_TOKEN")
|
||||
FIREBASE_BUCKET = os.getenv('FIREBASE_BUCKET')
|
||||
|
||||
# POST TO CREATE VIDEO
|
||||
POST_HEADER = {
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"Authorization": f"Bearer {TOKEN}"
|
||||
}
|
||||
GET_HEADER = {
|
||||
"accept": "application/json",
|
||||
"Authorization": f"Bearer {TOKEN}"
|
||||
}
|
||||
|
||||
|
||||
def create_videos_and_save_to_db(exercises, template, id):
|
||||
avatar = random.choice(list(AvatarEnum))
|
||||
# Speaking 1
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_1 = [element for element in exercises if element.get('type') == 1]
|
||||
# Check if any elements were found
|
||||
if found_exercises_1:
|
||||
exercise_1 = found_exercises_1[0]
|
||||
sp1_questions = []
|
||||
logger.info('Creating video for speaking part 1')
|
||||
for question in exercise_1["questions"]:
|
||||
sp1_result = create_video(question, avatar)
|
||||
if sp1_result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + sp1_result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp1_result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
video = {
|
||||
"text": question,
|
||||
"video_path": firebase_file_path,
|
||||
"video_url": url
|
||||
}
|
||||
sp1_questions.append(video)
|
||||
else:
|
||||
logger.error("Failed to create video for part 1 question: " + exercise_1["question"])
|
||||
template["exercises"][0]["prompts"] = sp1_questions
|
||||
template["exercises"][0]["first_title"] = exercise_1["first_topic"]
|
||||
template["exercises"][0]["second_title"] = exercise_1["second_topic"]
|
||||
|
||||
# Speaking 2
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_2 = [element for element in exercises if element.get('type') == 2]
|
||||
# Check if any elements were found
|
||||
if found_exercises_2:
|
||||
exercise_2 = found_exercises_2[0]
|
||||
logger.info('Creating video for speaking part 2')
|
||||
sp2_result = create_video(exercise_2["question"], avatar)
|
||||
if sp2_result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + sp2_result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp2_result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
sp2_video_path = firebase_file_path
|
||||
sp2_video_url = url
|
||||
template["exercises"][1]["prompts"] = exercise_2["prompts"]
|
||||
template["exercises"][1]["text"] = exercise_2["question"]
|
||||
template["exercises"][1]["title"] = exercise_2["topic"]
|
||||
template["exercises"][1]["video_url"] = sp2_video_url
|
||||
template["exercises"][1]["video_path"] = sp2_video_path
|
||||
else:
|
||||
logger.error("Failed to create video for part 2 question: " + exercise_2["question"])
|
||||
|
||||
# Speaking 3
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_3 = [element for element in exercises if element.get('type') == 3]
|
||||
# Check if any elements were found
|
||||
if found_exercises_3:
|
||||
exercise_3 = found_exercises_3[0]
|
||||
sp3_questions = []
|
||||
logger.info('Creating videos for speaking part 3')
|
||||
for question in exercise_3["questions"]:
|
||||
result = create_video(question, avatar)
|
||||
if result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
video = {
|
||||
"text": question,
|
||||
"video_path": firebase_file_path,
|
||||
"video_url": url
|
||||
}
|
||||
sp3_questions.append(video)
|
||||
else:
|
||||
logger.error("Failed to create video for part 3 question: " + question)
|
||||
template["exercises"][2]["prompts"] = sp3_questions
|
||||
template["exercises"][2]["title"] = exercise_3["topic"]
|
||||
|
||||
if not found_exercises_3:
|
||||
template["exercises"].pop(2)
|
||||
if not found_exercises_2:
|
||||
template["exercises"].pop(1)
|
||||
if not found_exercises_1:
|
||||
template["exercises"].pop(0)
|
||||
|
||||
save_to_db_with_id("speaking", template, id)
|
||||
logger.info('Saved speaking to DB with id ' + id + " : " + str(template))
|
||||
|
||||
|
||||
def create_video(text, avatar):
|
||||
# POST TO CREATE VIDEO
|
||||
create_video_url = "https://apis.elai.io/api/v1/videos"
|
||||
|
||||
avatar_url = AvatarEnum[avatar].value.get("avatar_url")
|
||||
avatar_code = AvatarEnum[avatar].value.get("avatar_code")
|
||||
avatar_gender = AvatarEnum[avatar].value.get("avatar_gender")
|
||||
avatar_canvas = AvatarEnum[avatar].value.get("avatar_canvas")
|
||||
voice_id = AvatarEnum[avatar].value.get("voice_id")
|
||||
voice_provider = AvatarEnum[avatar].value.get("voice_provider")
|
||||
|
||||
data = {
|
||||
"name": "API test",
|
||||
"slides": [
|
||||
{
|
||||
"id": 1,
|
||||
"canvas": {
|
||||
"objects": [
|
||||
{
|
||||
"type": "avatar",
|
||||
"left": 151.5,
|
||||
"top": 36,
|
||||
"fill": "#4868FF",
|
||||
"scaleX": 0.3,
|
||||
"scaleY": 0.3,
|
||||
"width": 1080,
|
||||
"height": 1080,
|
||||
"src": avatar_url,
|
||||
"avatarType": "transparent",
|
||||
"animation": {
|
||||
"type": None,
|
||||
"exitType": None
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "image",
|
||||
"version": "5.3.0",
|
||||
"originX": "left",
|
||||
"originY": "top",
|
||||
"left": 30,
|
||||
"top": 30,
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"fill": "rgb(0,0,0)",
|
||||
"stroke": None,
|
||||
"strokeWidth": 0,
|
||||
"strokeDashArray": None,
|
||||
"strokeLineCap": "butt",
|
||||
"strokeDashOffset": 0,
|
||||
"strokeLineJoin": "miter",
|
||||
"strokeUniform": False,
|
||||
"strokeMiterLimit": 4,
|
||||
"scaleX": 0.18821429,
|
||||
"scaleY": 0.18821429,
|
||||
"angle": 0,
|
||||
"flipX": False,
|
||||
"flipY": False,
|
||||
"opacity": 1,
|
||||
"shadow": None,
|
||||
"visible": True,
|
||||
"backgroundColor": "",
|
||||
"fillRule": "nonzero",
|
||||
"paintFirst": "fill",
|
||||
"globalCompositeOperation": "source-over",
|
||||
"skewX": 0,
|
||||
"skewY": 0,
|
||||
"cropX": 0,
|
||||
"cropY": 0,
|
||||
"id": 676845479989,
|
||||
"src": "https://d3u63mhbhkevz8.cloudfront.net/production/uploads/66f5190349f943682dd776ff/"
|
||||
"en-coach-main-logo-800x600_sm1ype.jpg?Expires=1727654400&Policy=eyJTdGF0ZW1lbnQiOlt"
|
||||
"7IlJlc291cmNlIjoiaHR0cHM6Ly9kM3U2M21oYmhrZXZ6OC5jbG91ZGZyb250Lm5ldC9wcm9kdWN0aW9uL3"
|
||||
"VwbG9hZHMvNjZmNTE5MDM0OWY5NDM2ODJkZDc3NmZmL2VuLWNvYWNoLW1haW4tbG9nby04MDB4NjAwX3NtM"
|
||||
"XlwZS5qcGciLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE3Mjc2NTQ0"
|
||||
"MDB9fX1dfQ__&Signature=kTVzlDeS7cua2HiAE5G%7E-yFqbhu0bHraFH5SauUln7yuNXoX7vtiKIBYiL"
|
||||
"%7Eps3LCLEZS77arSZ7H%7EG8CKzabHDjAR-Y6Uc%7ELD5KQaMmk0jbAxbC3Wdoq6cfd0qIwEuodQYlC0It"
|
||||
"2WBidP8KsgOy3uUQ%7EvcBoqlb255yMFw4pHuptOBB1kPs%7EFyzDV0fnRNsKaYRcy0Fn2EFUp13axm0CZQ"
|
||||
"clazuLFM622AyCydKMy0vfxV%7Etny3sskwPaUe2OANGMFg07Q1pRuy6fUON0DsbhAh1tA2H6-nnem5KbFw"
|
||||
"iZK3IIwwYGBx3H41ovzC6Ejt80Fd0%7EPSHw7GzVBnUmtP-IA__&Key-Pair-Id=K1Y7U91AR6T7E5",
|
||||
"crossOrigin": "anonymous",
|
||||
"filters": [],
|
||||
"_exists": True
|
||||
}
|
||||
],
|
||||
"background": "#ffffff",
|
||||
"version": "4.4.0"
|
||||
},
|
||||
"avatar": {
|
||||
"code": avatar_code,
|
||||
"gender": avatar_gender,
|
||||
"canvas": avatar_canvas
|
||||
},
|
||||
"animation": "fade_in",
|
||||
"language": "English",
|
||||
"speech": text,
|
||||
"voice": voice_id,
|
||||
"voiceType": "text",
|
||||
"voiceProvider": voice_provider
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
response = requests.post(create_video_url, headers=POST_HEADER, json=data)
|
||||
logger.info(response.status_code)
|
||||
logger.info(response.json())
|
||||
|
||||
video_id = response.json()["_id"]
|
||||
|
||||
if video_id:
|
||||
# Render Video
|
||||
render_url = f"https://apis.elai.io/api/v1/videos/render/{video_id}"
|
||||
|
||||
requests.post(render_url, headers=GET_HEADER)
|
||||
|
||||
status_url = f"https://apis.elai.io/api/v1/videos/{video_id}"
|
||||
|
||||
while True:
|
||||
response = requests.get(status_url, headers=GET_HEADER)
|
||||
response_data = response.json()
|
||||
|
||||
if response_data['status'] == 'ready':
|
||||
logger.info(response_data)
|
||||
# DOWNLOAD VIDEO
|
||||
download_url = response_data.get('url')
|
||||
output_directory = 'download-video/'
|
||||
output_filename = video_id + '.mp4'
|
||||
|
||||
response = requests.get(download_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
os.makedirs(output_directory, exist_ok=True) # Create the directory if it doesn't exist
|
||||
output_path = os.path.join(output_directory, output_filename)
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
logger.info(f"File '{output_filename}' downloaded successfully.")
|
||||
return output_filename
|
||||
else:
|
||||
logger.error(f"Failed to download file. Status code: {response.status_code}")
|
||||
return None
|
||||
elif response_data['status'] == 'failed':
|
||||
print('Video creation failed.')
|
||||
break
|
||||
else:
|
||||
print('Video is still processing. Checking again in 10 seconds...')
|
||||
time.sleep(10)
|
||||
@@ -1,179 +0,0 @@
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
from logging import getLogger
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from helper.constants import *
|
||||
from helper.firebase_helper import upload_file_firebase_get_url, save_to_db_with_id
|
||||
from heygen.AvatarEnum import AvatarEnum
|
||||
|
||||
load_dotenv()
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
# Get HeyGen token
|
||||
TOKEN = os.getenv("HEY_GEN_TOKEN")
|
||||
FIREBASE_BUCKET = os.getenv('FIREBASE_BUCKET')
|
||||
|
||||
# POST TO CREATE VIDEO
|
||||
CREATE_VIDEO_URL = 'https://api.heygen.com/v1/template.generate'
|
||||
GET_VIDEO_URL = 'https://api.heygen.com/v1/video_status.get'
|
||||
POST_HEADER = {
|
||||
'X-Api-Key': TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
GET_HEADER = {
|
||||
'X-Api-Key': TOKEN
|
||||
}
|
||||
|
||||
|
||||
def create_videos_and_save_to_db(exercises, template, id):
|
||||
avatar = random.choice(list(AvatarEnum))
|
||||
# Speaking 1
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_1 = [element for element in exercises if element.get('type') == 1]
|
||||
# Check if any elements were found
|
||||
if found_exercises_1:
|
||||
exercise_1 = found_exercises_1[0]
|
||||
sp1_questions = []
|
||||
logger.info('Creating video for speaking part 1')
|
||||
for question in exercise_1["questions"]:
|
||||
sp1_result = create_video(question, avatar)
|
||||
if sp1_result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + sp1_result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp1_result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
video = {
|
||||
"text": question,
|
||||
"video_path": firebase_file_path,
|
||||
"video_url": url
|
||||
}
|
||||
sp1_questions.append(video)
|
||||
else:
|
||||
logger.error("Failed to create video for part 1 question: " + exercise_1["question"])
|
||||
template["exercises"][0]["prompts"] = sp1_questions
|
||||
template["exercises"][0]["first_title"] = exercise_1["first_topic"]
|
||||
template["exercises"][0]["second_title"] = exercise_1["second_topic"]
|
||||
|
||||
# Speaking 2
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_2 = [element for element in exercises if element.get('type') == 2]
|
||||
# Check if any elements were found
|
||||
if found_exercises_2:
|
||||
exercise_2 = found_exercises_2[0]
|
||||
logger.info('Creating video for speaking part 2')
|
||||
sp2_result = create_video(exercise_2["question"], avatar)
|
||||
if sp2_result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + sp2_result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp2_result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
sp2_video_path = firebase_file_path
|
||||
sp2_video_url = url
|
||||
template["exercises"][1]["prompts"] = exercise_2["prompts"]
|
||||
template["exercises"][1]["text"] = exercise_2["question"]
|
||||
template["exercises"][1]["title"] = exercise_2["topic"]
|
||||
template["exercises"][1]["video_url"] = sp2_video_url
|
||||
template["exercises"][1]["video_path"] = sp2_video_path
|
||||
else:
|
||||
logger.error("Failed to create video for part 2 question: " + exercise_2["question"])
|
||||
|
||||
# Speaking 3
|
||||
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||
found_exercises_3 = [element for element in exercises if element.get('type') == 3]
|
||||
# Check if any elements were found
|
||||
if found_exercises_3:
|
||||
exercise_3 = found_exercises_3[0]
|
||||
sp3_questions = []
|
||||
logger.info('Creating videos for speaking part 3')
|
||||
for question in exercise_3["questions"]:
|
||||
result = create_video(question, avatar)
|
||||
if result is not None:
|
||||
sound_file_path = VIDEO_FILES_PATH + result
|
||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + result
|
||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||
video = {
|
||||
"text": question,
|
||||
"video_path": firebase_file_path,
|
||||
"video_url": url
|
||||
}
|
||||
sp3_questions.append(video)
|
||||
else:
|
||||
logger.error("Failed to create video for part 3 question: " + question)
|
||||
template["exercises"][2]["prompts"] = sp3_questions
|
||||
template["exercises"][2]["title"] = exercise_3["topic"]
|
||||
|
||||
if not found_exercises_3:
|
||||
template["exercises"].pop(2)
|
||||
if not found_exercises_2:
|
||||
template["exercises"].pop(1)
|
||||
if not found_exercises_1:
|
||||
template["exercises"].pop(0)
|
||||
|
||||
save_to_db_with_id("speaking", template, id)
|
||||
logger.info('Saved speaking to DB with id ' + id + " : " + str(template))
|
||||
|
||||
|
||||
def create_video(text, avatar):
|
||||
# POST TO CREATE VIDEO
|
||||
create_video_url = 'https://api.heygen.com/v2/template/' + avatar + '/generate'
|
||||
data = {
|
||||
"test": False,
|
||||
"caption": False,
|
||||
"title": "video_title",
|
||||
"variables": {
|
||||
"script_here": {
|
||||
"name": "script_here",
|
||||
"type": "text",
|
||||
"properties": {
|
||||
"content": text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
response = requests.post(create_video_url, headers=POST_HEADER, json=data)
|
||||
logger.info(response.status_code)
|
||||
logger.info(response.json())
|
||||
|
||||
# GET TO CHECK STATUS AND GET VIDEO WHEN READY
|
||||
video_id = response.json()["data"]["video_id"]
|
||||
params = {
|
||||
'video_id': response.json()["data"]["video_id"]
|
||||
}
|
||||
response = {}
|
||||
status = "processing"
|
||||
error = None
|
||||
|
||||
while status != "completed" and error is None:
|
||||
response = requests.get(GET_VIDEO_URL, headers=GET_HEADER, params=params)
|
||||
response_data = response.json()
|
||||
|
||||
status = response_data["data"]["status"]
|
||||
error = response_data["data"]["error"]
|
||||
|
||||
if status != "completed" and error is None:
|
||||
logger.info(f"Status: {status}")
|
||||
time.sleep(10) # Wait for 10 second before the next request
|
||||
|
||||
logger.info(response.status_code)
|
||||
logger.info(response.json())
|
||||
|
||||
# DOWNLOAD VIDEO
|
||||
download_url = response.json()['data']['video_url']
|
||||
output_directory = 'download-video/'
|
||||
output_filename = video_id + '.mp4'
|
||||
|
||||
response = requests.get(download_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
os.makedirs(output_directory, exist_ok=True) # Create the directory if it doesn't exist
|
||||
output_path = os.path.join(output_directory, output_filename)
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
logger.info(f"File '{output_filename}' downloaded successfully.")
|
||||
return output_filename
|
||||
else:
|
||||
logger.error(f"Failed to download file. Status code: {response.status_code}")
|
||||
return None
|
||||
@@ -1,11 +0,0 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class AvatarEnum(Enum):
|
||||
MATTHEW_NOAH = "5912afa7c77c47d3883af3d874047aaf"
|
||||
VERA_CERISE = "9e58d96a383e4568a7f1e49df549e0e4"
|
||||
EDWARD_TONY = "d2cdd9c0379a4d06ae2afb6e5039bd0c"
|
||||
TANYA_MOLLY = "045cb5dcd00042b3a1e4f3bc1c12176b"
|
||||
KAYLA_ABBI = "1ae1e5396cc444bfad332155fdb7a934"
|
||||
JEROME_RYAN = "0ee6aa7cc1084063a630ae514fccaa31"
|
||||
TYLER_CHRISTOPHER = "5772cff935844516ad7eeff21f839e43"
|
||||
8572
heygen/avatars.json
8572
heygen/avatars.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
13777
heygen/voices.json
13777
heygen/voices.json
File diff suppressed because it is too large
Load Diff
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user