o2o-castad-backend/poc/crawling/creatomate/creatomate.py

207 lines
8.9 KiB
Python

import requests
import copy
CREATOMATE_API_KEY = "df9e4382d7e84fe790bf8a2168152be195d5a3568524ceb66ed989a2dea809f7d3065d6803b2e3dd9d02b5e5ec1c9823"
#ACCOUNT_URL = "https://ado2mediastoragepublic.blob.core.windows.net/ado2-media-public-access/ado2-media-original/"
# Creatomate 템플릿 정보 전부 가져오기
class Creatomate():
base_url : str = "https://api.creatomate.com"
def __init__(self, api_key):
self.api_key = api_key
def get_all_templates_data(self) -> dict:
url = Creatomate.base_url + f"/v1/templates"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
response = requests.get(url, headers=headers)
return response.json()
# Creatomate 템플릿 ID 로부터 해당 템플릿 정보 가져오기
def get_one_template_data(self, template_id:str) -> dict:
url = Creatomate.base_url + f"/v1/templates/{template_id}"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
response = requests.get(url, headers=headers)
return response.json()
# 템플릿 정보 파싱하여 리소스 이름 추출하기
def parse_template_component_name(self, template_source : dict) -> dict:
def recursive_parse_component(element:dict) -> dict:
if 'name' in element:
result_element_name_type = {element['name'] : element['type']}
else:
result_element_name_type = {}
if element['type'] == "composition":
minor_component_list = [recursive_parse_component(minor) for minor in element['elements']]
for minor_component in minor_component_list: ## WARNING : Same name component should shroud other component. be aware
result_element_name_type.update(minor_component)
return result_element_name_type
result = {}
for result_element_dict in [recursive_parse_component(component) for component in template_source]:
result.update(result_element_dict)
return result
# 템플릿 정보 이미지/가사/음악 리소스와 매핑하기
# 이미지는 순차적으로 집어넣기
# 가사는 개행마다 한 텍스트 삽입
# Template에 audio-music 항목이 있어야 함. (추가된 템플릿 Cafe뿐임)
def template_connect_resource_blackbox(self, template_id:str, image_url_list:list[str], lyric:str, music_url:str) -> dict:
template_data = self.get_one_template_data(template_id)
template_component_data = self.parse_template_component_name(template_data['source']['elements'])
lyric.replace("\r", "")
lyric_splited = lyric.split("\n")
modifications = {}
for idx, (template_component_name, template_type) in enumerate(template_component_data.items()):
match template_type:
case 'image':
modifications[template_component_name] = image_url_list[idx % len(image_url_list)]
case 'text':
modifications[template_component_name] = lyric_splited[idx % len(lyric_splited)]
modifications["audio-music"] = music_url
return modifications
def elements_connect_resource_blackbox(self, elements:list, image_url_list:list[str], lyric:str, music_url:str) -> dict:
template_component_data = self.parse_template_component_name(elements)
lyric.replace("\r", "")
lyric_splited = lyric.split("\n")
modifications = {}
for idx, (template_component_name, template_type) in enumerate(template_component_data.items()):
match template_type:
case 'image':
modifications[template_component_name] = image_url_list[idx % len(image_url_list)]
case 'text':
modifications[template_component_name] = lyric_splited[idx % len(lyric_splited)]
modifications["audio-music"] = music_url
return modifications
def modify_element(self, elements : list, modification : dict):
def recursive_modify(element:dict) -> dict:
if 'name' in element:
match element['type']:
case 'image':
element['source'] = modification[element['name']]
case 'audio':
element['source'] = modification.get(element['name'], "")
case 'video':
element['source'] = modification[element['name']]
case 'text':
element['source'] = modification.get(element['name'], "")
case 'composition':
for minor in element['elements']:
recursive_modify(minor)
for minor in elements:
recursive_modify(minor)
return elements
# Creatomate에 생성 요청
# response에 요청 정보 있으니 풀링 필요
def make_creatomate_call(self, template_id:str, modifications:dict):
url = Creatomate.base_url + f"/v2/renders"
data = {
"template_id": template_id,
"modifications": modifications
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
response = requests.post(url, json=data, headers=headers)
return response
# Creatomate에 생성 요청 without template
# response에 요청 정보 있으니 풀링 필요
def make_creatomate_custom_call(self, source:str):
url = Creatomate.base_url + f"/v2/renders"
data = source
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
response = requests.post(url, json=data, headers=headers)
return response
def calc_scene_duration(self, template : dict):
total_template_duration = 0
for elem in template['source']['elements']:
try:
if elem['type'] == 'audio':
continue
total_template_duration += elem['duration']
if 'animations' not in elem:
continue
for animation in elem['animations']:
assert(animation['time'] == 0) # 0이 아닌 경우 확인 필요
if animation['transition']:
total_template_duration -= animation['duration']
except:
print(elem)
return total_template_duration
def extend_template_duration(self, template : dict, target_duration : float):
template['duration'] = target_duration
total_template_duration = self.calc_scene_duration(template)
extend_rate = target_duration / total_template_duration
new_template = copy.deepcopy(template)
for elem in new_template['source']['elements']:
try:
if elem['type'] == 'audio':
continue
elem['duration'] = elem['duration'] * extend_rate
if 'animations' not in elem:
continue
for animation in elem['animations']:
assert(animation['time'] == 0) # 0이 아닌 경우 확인 필요
animation['duration'] = animation['duration'] * extend_rate
except:
print(elem)
return new_template
# Azure사용한 legacy 코드 원본
# def template_connect_resource_blackbox(template_id, user_idx, task_idx):
# secret_client = get_keyvault_client()
# account_url = secret_client.get_secret(BLOB_ACCOUNT_URL_KEY).value
# media_folder_path = f"{user_idx}/{task_idx}"
# lyric_path = f"{media_folder_path}/lyric.txt"
# lyric = az_storage.az_storage_read_ado2_media(lyric_path).readall().decode('UTF-8')
# media_list = az_storage.az_storage_get_ado2_media_list(media_folder_path)
# image_list = [media.name for media in media_list if '/crawling-images/' in media.name]
# template_data = get_one_template_data(template_id)
# template_component_data = parse_template_component_name(template_data['source']['elements'])
# lyric.replace("\r", "")
# lyric_splited = lyric.split("\n")
# modifications = {}
# for idx, (template_component_name, template_type) in enumerate(template_component_data.items()):
# match template_type:
# case 'image':
# modifications[template_component_name] = f"{account_url}/{BLOB_CONTAINER_NAME}/{image_list[idx % len(image_list)]}"
# case 'text':
# modifications[template_component_name] = lyric_splited[idx % len(lyric_splited)]
# modifications["audio-music"] = f"{account_url}/{BLOB_CONTAINER_NAME}/{BLOB_MEDIA_FOLDER}/{media_folder_path}/music_mureka.mp3"
# print(modifications)
# return modifications