quantumiracle-git/OpenBiDexHand
5
1import gradio as gr2import os3import random4import numpy as np5import pandas as pd6import gdown7import base648from time import gmtime, strftime9from csv import writer10import json11import zipfile12from os import listdir13from os.path import isfile, join, isdir14from datasets import load_dataset15from hfserver import HuggingFaceDatasetSaver, HuggingFaceDatasetJSONSaver16 17ENVS = ['ShadowHand', 'ShadowHandCatchAbreast', 'ShadowHandOver', 'ShadowHandBlockStack', 'ShadowHandCatchUnderarm',18'ShadowHandCatchOver2Underarm', 'ShadowHandBottleCap', 'ShadowHandLiftUnderarm', 'ShadowHandTwoCatchUnderarm',19'ShadowHandDoorOpenInward', 'ShadowHandDoorOpenOutward', 'ShadowHandDoorCloseInward', 'ShadowHandDoorCloseOutward',20'ShadowHandPushBlock', 'ShadowHandKettle', 21'ShadowHandScissors', 'ShadowHandPen', 'ShadowHandSwingCup', 'ShadowHandGraspAndPlace', 'ShadowHandSwitch']22 23# download data from huggingface dataset24# dataset = load_dataset("quantumiracle-git/robotinder-data")25# os.remove('.git/hooks/pre-push') # https://github.com/git-lfs/git-lfs/issues/85326LOAD_DATA_GOOGLE_DRIVE = False27 28if LOAD_DATA_GOOGLE_DRIVE: # download data from google drive29 # url = 'https://drive.google.com/drive/folders/1JuNQS4R7axTezWj1x4KRAuRt_L26ApxA?usp=sharing' # './processed/' folder in google drive30 # url = 'https://drive.google.com/drive/folders/1o8Q9eX-J7F326zv4g2MZWlzR46uVkUF2?usp=sharing' # './processed_zip/' folder in google drive31 # url = 'https://drive.google.com/drive/folders/1ZWgpPiZwnWfwlwta8Tu-Jtu2HsS7HAEa?usp=share_link' # './filter_processed_zip/' folder in google drive32 # url = 'https://drive.google.com/drive/folders/1ROkuX6rQpyK7vLqF5fL2mggKiMCdKSuY?usp=share_link' # './split_processed_zip/' folder in google drive33 34 # output = './'35 # id = url.split('/')[-1]36 # os.system(f"gdown --id {id} -O {output} --folder --no-cookies --remaining-ok")37 # # VIDEO_PATH = 'processed_zip'38 # # VIDEO_PATH = 'filter_processed_zip'39 # VIDEO_PATH = 'split_processed_zip'40 41 # # unzip the zip files to the same location and delete zip files42 # path_to_zip_file = VIDEO_PATH43 # zip_files = [join(path_to_zip_file, f) for f in listdir(path_to_zip_file)]44 # for f in zip_files:45 # if f.endswith(".zip"):46 # directory_to_extract_to = path_to_zip_file # extracted file itself contains a folder47 # print(f'extract data {f} to {directory_to_extract_to}')48 # with zipfile.ZipFile(f, 'r') as zip_ref:49 # zip_ref.extractall(directory_to_extract_to)50 # os.remove(f)51 52 ### multiple urls to handle the retrieve error53 # urls = [54 # 'https://drive.google.com/drive/folders/1BbQe4XtcsalsvwGVLW9jWCkr-ln5pvyf?usp=share_link', # './filter_processed_zip/1' folder in google drive55 # 'https://drive.google.com/drive/folders/1saUTUuObPhMJFguc2J_O0K5woCJjYHci?usp=share_link', # './filter_processed_zip/2' folder in google drive56 # 'https://drive.google.com/drive/folders/1Kh9_E28-RH8g8EP1V3DhGI7KRs9LB7YJ?usp=share_link', # './filter_processed_zip/3' folder in google drive57 # 'https://drive.google.com/drive/folders/1oE75Dz6hxtaSpNhjD22PmQfgQ-PjnEc0?usp=share_link', # './filter_processed_zip/4' folder in google drive58 # 'https://drive.google.com/drive/folders/1XSPEKFqNHpXdLho-bnkT6FZZXssW8JkC?usp=share_link', # './filter_processed_zip/5' folder in google drive59 # 'https://drive.google.com/drive/folders/1XwjAHqR7kF1uSyZZIydQMoETfdvi0aPD?usp=share_link',60 # 'https://drive.google.com/drive/folders/1TceozOWhLsbqP-w-RkforjAVo1M2zsRP?usp=share_link',61 # 'https://drive.google.com/drive/folders/1zAP9eDSW5Eh_isACuZJadXcFaJNqEM9u?usp=share_link',62 # 'https://drive.google.com/drive/folders/1oK8fyF9A3Pv5JubvrQMjTE9n66vYlyZN?usp=share_link',63 # 'https://drive.google.com/drive/folders/1cezGNjlM0ONMM6C0N_PbZVCGsTyVSR0w?usp=share_link',64 # ]65 66 urls = [67 'https://drive.google.com/drive/folders/1SF5jQ7HakO3lFXBon57VP83-AwfnrM3F?usp=share_link', # './split_processed_zip/1' folder in google drive68 'https://drive.google.com/drive/folders/13WuS6ow6sm7ws7A5xzCEhR-2XX_YiIu5?usp=share_link', # './split_processed_zip/2' folder in google drive69 'https://drive.google.com/drive/folders/1GWLffJDOyLkubF2C03UFcB7iFpzy1aDy?usp=share_link', # './split_processed_zip/3' folder in google drive70 'https://drive.google.com/drive/folders/1UKAntA7WliD84AUhRN224PkW4vt9agZW?usp=share_link', # './split_processed_zip/4' folder in google drive71 'https://drive.google.com/drive/folders/11cCQw3qb1vJbviVPfBnOVWVzD_VzHdWs?usp=share_link', # './split_processed_zip/5' folder in google drive72 'https://drive.google.com/drive/folders/1Wvy604wCxEdXAwE7r3sE0L0ieXvM__u8?usp=share_link',73 'https://drive.google.com/drive/folders/1BTv_pMTNGm7m3hD65IgBrX880v-rLIaf?usp=share_link',74 'https://drive.google.com/drive/folders/12x7F11ln2VQkqi8-Mu3kng74eLgifM0N?usp=share_link',75 'https://drive.google.com/drive/folders/1OWkOul2CCrqynqpt44Fu1CBxzNNfOFE2?usp=share_link',76 'https://drive.google.com/drive/folders/1ukwsfrbSEqCBNmRSuAYvYBHijWCQh2OU?usp=share_link',77 'https://drive.google.com/drive/folders/1EO7zumR6sVfsWQWCS6zfNs5WuO2Se6WX?usp=share_link',78 'https://drive.google.com/drive/folders/1aw0iBWvvZiSKng0ejRK8xbNoHLVUFCFu?usp=share_link',79 'https://drive.google.com/drive/folders/1szIcxlVyT5WJtzpqYWYlue0n82A6-xtk?usp=share_link',80 ]81 82 output = './'83 # VIDEO_PATH = 'processed_zip'84 # VIDEO_PATH = 'filter_processed_zip'85 VIDEO_PATH = 'split_processed_zip'86 for i, url in enumerate(urls):87 id = url.split('/')[-1]88 os.system(f"gdown --id {id} -O {output} --folder --no-cookies --remaining-ok")89 90 # unzip the zip files to the same location and delete zip files91 path_to_zip_file = str(i+1)92 zip_files = [join(path_to_zip_file, f) for f in listdir(path_to_zip_file)]93 for f in zip_files:94 if f.endswith(".zip"):95 directory_to_extract_to = VIDEO_PATH # extracted file itself contains a folder96 print(f'extract data {f} to {directory_to_extract_to}')97 with zipfile.ZipFile(f, 'r') as zip_ref:98 zip_ref.extractall(directory_to_extract_to)99 os.remove(f)100 101else:102 VIDEO_PATH = 'processed-data'103 path_to_zip_file = VIDEO_PATH104 zip_files = [join(path_to_zip_file, f) for f in listdir(path_to_zip_file)]105 for f in zip_files:106 if f.endswith(".zip"):107 directory_to_extract_to = path_to_zip_file # extracted file itself contains a folder108 print(f'extract data {f} to {directory_to_extract_to}')109 with zipfile.ZipFile(f, 'r') as zip_ref:110 zip_ref.extractall(directory_to_extract_to)111 os.remove(f)112 113# for test only114# else: # local data115# VIDEO_PATH = 'robotinder-data'116 117VIDEO_INFO = os.path.join(VIDEO_PATH, 'video_info.json')118 119def inference(video_path):120 # for displaying mp4 with autoplay on Gradio121 with open(video_path, "rb") as f:122 data = f.read()123 b64 = base64.b64encode(data).decode()124 html = (125 f"""126 <video controls autoplay muted loop>127 <source src="data:video/mp4;base64,{b64}" type="video/mp4">128 </video> 129 """130 )131 return html132 133def video_identity(video):134 return video135 136def nan():137 return None138 139FORMAT = ['mp4', 'gif'][0]140 141def get_huggingface_dataset():142 try:143 import huggingface_hub144 except (ImportError, ModuleNotFoundError):145 raise ImportError(146 "Package `huggingface_hub` not found is needed "147 "for HuggingFaceDatasetSaver. Try 'pip install huggingface_hub'."148 )149 HF_TOKEN = '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' # my HF token150 DATASET_NAME = 'crowdsourced-robotinder-demo'151 FLAGGING_DIR = 'flag/'152 path_to_dataset_repo = huggingface_hub.create_repo(153 repo_id=DATASET_NAME,154 token=HF_TOKEN,155 private=False,156 repo_type="dataset",157 exist_ok=True,158 ) 159 dataset_dir = os.path.join(DATASET_NAME, FLAGGING_DIR)160 repo = huggingface_hub.Repository(161 local_dir=dataset_dir,162 clone_from=path_to_dataset_repo,163 use_auth_token=HF_TOKEN,164 )165 repo.git_pull(lfs=True)166 log_file = os.path.join(dataset_dir, "flag_data.csv")167 return repo, log_file168 169def update(user_choice, user_name, left, right, choose_env, data_folder=VIDEO_PATH, flag_to_huggingface=False):170 global last_left_video_path 171 global last_right_video_path 172 global last_infer_left_video_path173 global last_infer_right_video_path174 175 if flag_to_huggingface: # log176 env_name = str(last_left_video_path).split('/')[1] # 'robotinder-data/ENV_NAME/'177 current_time = strftime("%Y-%m-%d-%H-%M-%S", gmtime())178 info = [env_name, user_choice, last_left_video_path, last_right_video_path, current_time, user_name]179 print(info)180 repo, log_file = get_huggingface_dataset()181 with open(log_file, 'a') as file: # incremental change of the file182 writer_object = writer(file)183 writer_object.writerow(info)184 file.close()185 if int(current_time.split('-')[-2]) % 5 == 0: # push only on certain minutes186 try:187 repo.push_to_hub(commit_message=f"Flagged sample at {current_time}")188 except:189 repo.git_pull(lfs=True) # sync with remote first190 repo.push_to_hub(commit_message=f"Flagged sample at {current_time}")191 if choose_env == 'Random' or choose_env == '': # random or no selection192 envs = get_env_names() 193 env_name = envs[random.randint(0, len(envs)-1)]194 else:195 env_name = choose_env196 # choose video197 left, right = randomly_select_videos(env_name)198 199 last_left_video_path = left200 last_right_video_path = right201 last_infer_left_video_path = inference(left)202 last_infer_right_video_path = inference(right)203 204 return last_infer_left_video_path, last_infer_right_video_path, env_name205 206def replay(left, right): 207 return left, right208 209def parse_envs(folder=VIDEO_PATH, filter=True, MAX_ITER=20000, DEFAULT_ITER=20000):210 """211 return a dict of env_name: video_paths212 """213 files = {}214 if filter:215 df = pd.read_csv('Bidexhands_Video.csv')216 # print(df)217 for env_name in os.listdir(folder):218 env_path = os.path.join(folder, env_name)219 if os.path.isdir(env_path):220 videos = os.listdir(env_path)221 video_files = []222 for video in videos: # video name rule: EnvName_Alg_Seed_Timestamp_Checkpoint_video-episode-EpisodeID223 if video.endswith(f'.{FORMAT}'):224 if filter:225 if len(video.split('_')) < 6:226 print(f'{video} is wrongly named.')227 seed = video.split('_')[2]228 checkpoint = video.split('_')[4]229 try:230 succeed_iteration = df.loc[(df['seed'] == int(seed)) & (df['env_name'] == str(env_name))]['succeed_iteration'].iloc[0]231 except:232 print(f'Env {env_name} with seed {seed} not found in Bidexhands_Video.csv')233 234 if 'unsolved' in succeed_iteration:235 continue236 elif pd.isnull(succeed_iteration):237 min_iter = DEFAULT_ITER238 max_iter = MAX_ITER239 elif '-' in succeed_iteration:240 [min_iter, max_iter] = succeed_iteration.split('-')241 else:242 min_iter = succeed_iteration243 max_iter = MAX_ITER244 245 # check if the checkpoint is in the valid range246 valid_checkpoints = np.arange(int(min_iter), int(max_iter)+1000, 1000)247 if int(checkpoint) not in valid_checkpoints:248 continue249 250 video_path = os.path.join(folder, env_name, video)251 video_files.append(video_path)252 # print(video_path)253 254 files[env_name] = video_files255 256 with open(VIDEO_INFO, 'w') as fp:257 json.dump(files, fp)258 259 return files260 261def get_env_names():262 with open(VIDEO_INFO, 'r') as fp:263 files = json.load(fp)264 return list(files.keys())265 266def randomly_select_videos(env_name):267 # load the parsed video info268 with open(VIDEO_INFO, 'r') as fp:269 files = json.load(fp)270 env_files = files[env_name]271 # randomly choose two videos272 selected_video_ids = np.random.choice(len(env_files), 2, replace=False)273 left_video_path = env_files[selected_video_ids[0]]274 right_video_path = env_files[selected_video_ids[1]]275 return left_video_path, right_video_path276 277def build_interface(iter=3, data_folder=VIDEO_PATH):278 import sys279 import csv280 csv.field_size_limit(sys.maxsize)281 282 HF_TOKEN = os.getenv('HF_TOKEN')283 print(HF_TOKEN)284 HF_TOKEN = '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' # my HF token285 ## hf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, "crowdsourced-robotinder-demo") # HuggingFace logger instead of local one: https://github.com/gradio-app/gradio/blob/master/gradio/flagging.py286 ## callback = gr.CSVLogger()287 # hf_writer = HuggingFaceDatasetSaver(HF_TOKEN, "crowdsourced-robotinder-demo")288 # callback = hf_writer289 290 # parse the video folder 291 files = parse_envs() 292 293 # build gradio interface294 with gr.Blocks() as demo:295 # gr.Markdown("## Here is <span style=color:cyan>RoboTinder</span>!")296 gr.Markdown("### Select the best robot behaviour in your choice!")297 # some initial values298 env_name = list(files.keys())[random.randint(0, len(files)-1)] # random pick an env 299 with gr.Row():300 str_env_name = gr.Markdown(f"{env_name}")301 302 # choose video303 left_video_path, right_video_path = randomly_select_videos(env_name)304 305 with gr.Row():306 if FORMAT == 'mp4':307 # left = gr.PlayableVideo(left_video_path, label="left_video")308 # right = gr.PlayableVideo(right_video_path, label="right_video")309 310 infer_left_video_path = inference(left_video_path)311 infer_right_video_path = inference(right_video_path)312 left = gr.HTML(infer_left_video_path, label="left_video")313 right = gr.HTML(infer_right_video_path, label="right_video")314 else:315 left = gr.Image(left_video_path, shape=(1024, 768), label="left_video")316 # right = gr.Image(right_video_path).style(height=768, width=1024)317 right = gr.Image(right_video_path, label="right_video")318 319 global last_left_video_path 320 last_left_video_path = left_video_path321 global last_right_video_path 322 last_right_video_path = right_video_path323 324 global last_infer_left_video_path325 last_infer_left_video_path = infer_left_video_path326 global last_infer_right_video_path327 last_infer_right_video_path = infer_right_video_path328 329 # btn1 = gr.Button("Replay")330 user_name = gr.Textbox(label='Your name/email:')331 # user_choice = gr.Radio(["Left", "Right", "Not Sure", "Both Good", "Both Bad"], label="Which one is your favorite?")332 user_choice = gr.Radio(["Left", "Right", "Not Sure"], label="Which one is your favorite?")333 choose_env = gr.Radio(["Random"]+ENVS, label="Choose the next task:")334 btn2 = gr.Button("Next")335 336 # This needs to be called at some point prior to the first call to callback.flag()337 # callback.setup([user_choice, left, right], "flagged_data_points")338 339 # btn1.click(fn=replay, inputs=[left, right], outputs=[left, right])340 btn2.click(fn=update, inputs=[user_choice, user_name, left, right, choose_env], outputs=[left, right, str_env_name])341 342 # We can choose which components to flag -- in this case, we'll flag all of them343 # btn2.click(lambda *args: callback.flag(args), [user_choice, left, right], None, preprocess=False) # not using the gradio flagging anymore344 345 return demo346 347if __name__ == "__main__":348 last_left_video_path = None349 last_right_video_path = None350 351 demo = build_interface()352 # demo.launch(share=True)353 demo.launch(share=False)354 