import math import os import requests from pprint import pprint import argparse import soundfile class A2F(object): ROOT_PATH = "/home/ubuntu/results" BASE_PATH = os.path.expanduser("~/.local/share/ov/pkg/audio2face-2023.2.0/") ASSETS_PATH = os.path.join(BASE_PATH, "exts/omni.audio2face.tool/deps/audio2face-assets") CLAIRE_PATH = os.path.join(ASSETS_PATH, "claire/mesh/claire_fullface_model.usd") MARK_PATH = os.path.join(ASSETS_PATH, "mark/mesh/mark_fullface_model.usd") PLAYER_NAME = "/World/audio2face/Player" FULLFACE_MODEL_NAME = "/World/audio2face/CoreFullface" def __init__(self, url="http://localhost:8011/"): self.url = url def status(self): resp = requests.get(f"{self.url}status") return resp.json() def get_emotion_names(self): resp = requests.get(f"{self.url}A2F/A2E/GetEmotionNames") return resp.json().get('result', []) def get_scene_objects(self): resp = requests.get(f"{self.url}A2F/GetInstances") return resp.json().get('result', {}) def get_players(self): resp = requests.get(f"{self.url}A2F/Player/GetInstances") return resp.json().get('result', {}) def load_usd(self, usd_path): resp = requests.post(f"{self.url}A2F/USD/Load", json={ "file_name": usd_path, }) return resp.json() def load_claire(self): print("Claire path: ", self.CLAIRE_PATH) return self.load_usd(self.CLAIRE_PATH) def load_mark(self): print("Mark path: ", self.MARK_PATH) return self.load_usd(self.MARK_PATH) def openapi(self): resp = requests.get(f"{self.url}openapi.json") return resp.json() def get_frame(self): pass def get_settings(self): resp = requests.post(f"{self.url}A2F/GetSettings", json={ "a2f_instance": "", }) return resp.json() def get_player_root(self): resp = requests.post(f"{self.url}A2F/Player/GetRootPath", json={ "a2f_player": self.PLAYER_NAME, }) return resp.json() def set_player_root(self, new_path): resp = requests.post(f"{self.url}A2F/Player/SetRootPath", json={ "a2f_player": self.PLAYER_NAME, "dir_path": new_path, }) return resp.json() def set_audio(self, audio_path): duration = soundfile.info(audio_path).duration print("Audio duration: ", duration) resp = requests.post(f"{self.url}A2F/Player/SetTrack", json={ "a2f_player": self.PLAYER_NAME, "file_name": audio_path, "time_range": [ 0, duration ] }) data = [resp.json()] resp = requests.post(f"{self.url}A2F/Player/SetRange", json={ "a2f_player": self.PLAYER_NAME, "start": 0, "end": duration }) data.append(resp.json()) resp = requests.post(f"{self.url}A2F/Player/GetTracks", json={ "a2f_player": self.PLAYER_NAME, }) data.append(resp.json()) resp = requests.post(f"{self.url}A2F/Player/GetCurrentTrack", json={ "a2f_player": self.PLAYER_NAME, }) data.append(resp.json()) return data def get_audio_range(self): resp = requests.post(f"{self.url}A2F/Player/GetRange", json={ "a2f_player": self.PLAYER_NAME, }) return resp.json() def run(self): resp = requests.post(f"{self.url}A2F/A2E/GenerateKeys", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def get_number_of_keys(self): resp = requests.post(f"{self.url}A2F/A2E/NumKeys", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def get_generated_keys(self): resp = requests.post(f"{self.url}A2F/A2E/GetKeyData", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def get_a2e_settings(self): resp = requests.post(f"{self.url}A2F/A2E/GetSettings", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def get_blendshape_solvers(self): resp = requests.get(f"{self.url}A2F/Exporter/GetBlendShapeSolvers") return resp.json() def get_pre_settings(self): resp = requests.post(f"{self.url}A2F/PRE/SetSettings", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, "prediction_delay": 0.01, }) resp = requests.post(f"{self.url}A2F/PRE/GetSettings", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def get_post_settings(self): resp = requests.post(f"{self.url}A2F/POST/GetSettings", json={ "a2f_instance": self.FULLFACE_MODEL_NAME, }) return resp.json() def export(self, export_path, filename): resp = requests.post(f"{self.url}A2F/Exporter/ExportGeometryCache", json={ "export_directory": export_path, "cache_type": "usd", "xform_keys": False, "batch": False, "file_name": filename, "fps": 0 }) try: return resp.json() except: print(resp.content) def export_json(self, export_path, filename): resp = requests.post(f"{self.url}A2F/Exporter/ExportBlendshapes", json={ "export_directory": export_path, "format": "json", "batch": False, "file_name": filename, "fps": 0 }) try: return resp.json() except: print(resp.content) def upload(self, audio_path): audio_path = os.path.abspath(audio_path) fname = os.path.basename(audio_path) os.system(f"cd ./server && ./send_file_to_gui.sh {audio_path} ../results/{fname}") return os.path.join("/home/ubuntu/results", fname) def pull(self, fname): export_fname = os.path.splitext(fname)[0] + '.usd' os.system(f"cd ./server && ./send_file_from_gui.sh ../results/{export_fname} ../") def apply(self, audio_path): fname = os.path.basename(audio_path) print("Status: ", self.status()) print("EmotionNames: ", self.get_emotion_names()) print("Scene Objects: ", self.get_scene_objects()) print("Scene Players: ", self.get_players()) print("Preprocessing settings: ", self.get_pre_settings()) print("Postprocessing settings: ", self.get_post_settings()) print("Setting player root: ", self.set_player_root("/home/ubuntu/results")) print("Player root: ", self.get_player_root()) print("Setting audio: ", self.set_audio(os.path.basename(audio_path))) print("Audio Range: ", self.get_audio_range()) print("Running: ", self.run()) print("NumKeys: ", self.get_number_of_keys()) print("Keys: ", self.get_generated_keys()) print("Exporting: ", self.export_json("/home/ubuntu/results", filename=os.path.splitext(fname)[0])) def apply_stream(self, audio_path): pass