from otree.api import * from os import environ import pandas as pd import random import dropbox class C(BaseConstants): NAME_IN_URL = 'control' PLAYERS_PER_GROUP = 2 len_sequence = 13 num_sequences = 2 num_sets = 8 NUM_ROUNDS = num_sequences*num_sets columns = [f"c{i+1}" for i in range(len_sequence)] columns = columns + ["sequence_ID","trial","individual_ID","pair_ID","condition","accuracy"] list_seq_ID = [i+1 for i in range(num_sequences)] # minimum permissions app_key = environ.get('APP_KEY') app_secret = environ.get('APP_SECRET') refresh_token = environ.get('REFRESH_TOKEN') rdbx = dropbox.Dropbox(oauth2_refresh_token=refresh_token, app_key=app_key, app_secret=app_secret) rdbx.refresh_access_token() access_token = rdbx._oauth2_access_token class Product(ExtraModel): c1 = models.StringField() c2 = models.StringField() c3 = models.StringField() c4 = models.StringField() c5 = models.StringField() c6 = models.StringField() c7 = models.StringField() c8 = models.StringField() c9 = models.StringField() c10 = models.StringField() c11 = models.StringField() c12 = models.StringField() c13 = models.StringField() sequence_ID = models.IntegerField() trial = models.IntegerField() individual_ID = models.IntegerField() pair_ID = models.IntegerField() condition = models.IntegerField() accuracy = models.FloatField() class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): age = models.IntegerField(label='年齢', min=0, max=100) gender = models.StringField( choices=[['Male', '男'], ['Female', '女']], label='性別を入力してください。', widget=widgets.RadioSelect, ) player_id = models.IntegerField(label='ID') sequence = models.StringField(label="") Learn_seq = models.StringField() sequence_ID = models.IntegerField() pair_ID = models.IntegerField() condition = models.IntegerField() accuracy = models.FloatField() def getDF(self): seed_id = self.player_id temp = read_csv(f"control/Seed/{seed_id}.csv", Product) temp = pd.DataFrame.from_dict(temp) self.participant.vars['prev_df'] = temp self.participant.vars['df_reproduced'] = pd.DataFrame(columns=C.columns) def update_dataframe(player,sequence): player_info = player.in_round(1) # get demographic information player_id = str(player_info.player_id) condition = int(player_id[0]) pair_ID = int(player_id[1:3]) individual_ID = int(player_id[-1]) # update df_reproduced sequence = [str(s) for s in sequence] temp1 = pd.DataFrame( {"c1":sequence[0] ,"c2":sequence[1] ,"c3":sequence[2] ,"c4":sequence[3] ,"c5":sequence[4] ,"c6":sequence[5] ,"c7":sequence[6] ,"c8":sequence[7] ,"c9":sequence[8] ,"c10":sequence[9] ,"c11":sequence[10] ,"c12":sequence[11] ,"c13":sequence[12] ,"sequence_ID":player.sequence_ID ,"trial":player.round_number ,"individual_ID":individual_ID ,"pair_ID":pair_ID ,"condition":condition ,"accuracy":player.accuracy },index=[0]) player.participant.vars['df_reproduced'] = pd.concat([player.participant.vars['df_reproduced'],temp1],ignore_index=True) print(player.participant.vars['df_reproduced']) # update df_displayed Displayed_seq = player.Learn_seq temp2 = pd.DataFrame( {"c1":Displayed_seq[0] ,"c2":Displayed_seq[1] ,"c3":Displayed_seq[2] ,"c4":Displayed_seq[3] ,"c5":Displayed_seq[4] ,"c6":Displayed_seq[5] ,"c7":Displayed_seq[6] ,"c8":Displayed_seq[7] ,"c9":Displayed_seq[8] ,"c10":Displayed_seq[9] ,"c11":Displayed_seq[10] ,"c12":Displayed_seq[11] ,"c13":Displayed_seq[12] ,"sequence_ID":player.sequence_ID ,"trial":player.round_number ,"individual_ID":individual_ID ,"pair_ID":pair_ID ,"condition":condition ,"accuracy":player.accuracy },index=[0]) player.participant.vars['df_displayed'] = pd.concat([player.participant.vars['df_displayed'],temp2],ignore_index=True) print(player.participant.vars['df_displayed']) # compute accuracy def levenshtein(self, s1, s2): # len(s1) >= len(s2) if len(s1) < len(s2): return levenshtein(s2, s1) if len(s2) == 0: return len(s1) previous_row = range(len(s2) + 1) for i, c1 in enumerate(s1): current_row = [i + 1] for j, c2 in enumerate(s2): insertions = previous_row[j + 1] + 1 deletions = current_row[j] + 1 substitutions = previous_row[j] + (c1 != c2) current_row.append(min(insertions, deletions, substitutions)) previous_row = current_row return previous_row[-1] def to_dropbox(player,dataframe, path, token): dbx = dropbox.Dropbox(token) df_string = dataframe.to_csv(index=False) db_bytes = bytes(df_string, 'utf8') dbx.files_upload( f=db_bytes, path=path, mode=dropbox.files.WriteMode.overwrite ) # ERROR MESSAGE def player_id_error_message(player, value): #6桁の入力しか受け付けない。→あとでID重複チェックもつける。 print('player_id is', value) seed_id = value if len(str(value)) != 4: return 'ID番号を再入力してください' try: temp = read_csv(f"control/Seed/{value}.csv", Product) except FileNotFoundError: return 'ID番号を再入力してください' # FUNCTIONS # PAGES class Demographics(Page): @staticmethod def is_displayed(self): #list_seq_ID = random.sample(C.list_seq_ID, len(C.list_seq_ID)) list_seq_ID = [s for s in C.list_seq_ID] # copy self.participant.vars['list_seq_ID'] = list_seq_ID return self.round_number == 1 form_model = 'player' form_fields = ['player_id','age','gender'] class Instruction(Page): @staticmethod def is_displayed(self): return self.round_number == 1 form_model = 'player' @staticmethod def vars_for_template(self): self.getDF() print(self.participant.vars["prev_df"]) # Create dataframe to save current data self.participant.vars['df_displayed'] = pd.DataFrame(columns=C.columns) self.participant.vars['df_reproduced'] = pd.DataFrame(columns=C.columns) class Learning(Page): @staticmethod def js_vars(player): round_number = player.round_number num_sequences = C.num_sequences num_sets = C.num_sets if int((round_number-1)%num_sets) == 0: # read from seed displayed_ID = player.participant.vars['list_seq_ID'][int(round_number/num_sets)] print("displayed_ID:",displayed_ID) #player.sequence_ID = int(player.participant.vars["prev_df"].query(f"sequence_ID=={displayed_ID}")["sequence_ID"].values[0]) player.sequence_ID = displayed_ID Learn_seq = player.participant.vars["prev_df"].query(f"sequence_ID=={displayed_ID}").iloc[:,0:C.len_sequence].values.tolist()[0] print(Learn_seq) else: # read from repruduced sequences by a partner partner_info = player.get_others_in_group()[0] #displayed_ID = player.participant.vars['list_seq_ID'][round_number%C.num_sequences-1] displayed_ID = partner_info.participant.vars["df_reproduced"].query(f"trial=={round_number-1}").values.tolist()[0][C.len_sequence] print("displayed_ID:",displayed_ID) player.sequence_ID = displayed_ID Learn_seq = partner_info.participant.vars["df_reproduced"].query(f"trial=={round_number-1}").values.tolist()[0][:C.len_sequence] print(Learn_seq) player.Learn_seq = "".join(Learn_seq) # to save on oTree database return dict( Learn_seq=Learn_seq, ) class Reproduction(Page): form_model = 'player' form_fields = ['sequence'] @staticmethod def js_vars(player): len_sequence = C.len_sequence return dict(len_sequence=len_sequence-1) class Feedback(Page): timeout_seconds = 20 @staticmethod def vars_for_template(player): s1 = player.Learn_seq s2 = player.sequence print(s2) accuracy = 1 - (player.levenshtein(s1,s2) / len(s1)) player.accuracy = accuracy player.update_dataframe(player.sequence) player_info = player.in_round(1) # get demographic information player_id = str(player_info.player_id) path1 = f"/dataframes/{player_id}.csv" player.to_dropbox(dataframe=player.participant.vars['df_reproduced'], path=path1, token=C.access_token) path2 = f"/dataframes/displayed_{player_id}.csv" player.to_dropbox(dataframe=player.participant.vars['df_displayed'], path=path2, token=C.access_token) return dict(accuracy=round(accuracy*100)) class MyWait(WaitPage): template_name = 'control/MyWait.html' title_text = "Please wait a while" body_text = "Processing ..." @staticmethod def after_all_players_arrive(group: Group): for p in group.get_players(): player_info = p.in_round(1) # get demographic information player_id = str(player_info.player_id) condition = int(player_id[0]) pair_ID = int(player_id[1:3]) p.age = player_info.age p.gender = player_info.gender p.player_id = player_info.player_id p.pair_ID = pair_ID p.condition = condition class Finish(Page): @staticmethod def is_displayed(self): return self.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player): player_info = player.in_round(1) # get demographic information player_id = int(player_info.player_id) path1 = f"/dataframes/{player_id}.csv" player.to_dropbox(dataframe=player.participant.vars['df_reproduced'], path=path1, token=C.access_token) path2 = f"/dataframes/displayed_{player_id}.csv" player.to_dropbox(dataframe=player.participant.vars['df_displayed'], path=path2, token=C.access_token) page_sequence = [ Demographics ,Instruction ,Learning ,Reproduction ,Feedback ,MyWait ,Finish ]