import tweepy from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants from NewsSocialSignaling import TwitterAPI, TwitterProcessor import datetime as dt import json import numpy as np import hashlib def string2seed(seed_str): return int(hashlib.sha512(seed_str.encode('utf-8')).hexdigest(), 16) % 10000000 class Consent(Page): form_model = 'player' form_fields = ['twitterHandle'] live_method = 'live_handler' def twitterHandle_error_message(self, value): handle = value if value.startswith('@'): handle = value[1:] handle = handle.replace(' ', '') if len(handle) == 0: return 'Please enter your handle!' print(handle) # pull user data ts = dt.datetime.utcnow().timestamp() self.participant.vars['twitter_handle'] = handle if 'handles' not in self.participant.vars: self.participant.vars['handles'] = {} self.participant.vars['handles'][ts] = {'h': handle} try: u = TwitterAPI.get_user(screen_name=handle, get_friends=True, resample=True, return_errors=True, max_pages_network=2) except Exception as e: #if isinstance(e, tweepy.TweepError) and str(e).lower() == 'not authorized.': # self.participant.vars['handles'][ts] = {'error': 'protected'} # return 'It looks like you entered a Twitter handle for a protected account, unfortunately only public accounts are eligible for this ExperimentRT.' self.participant.vars['errors'] = str(e) raise e self.participant.vars['user_data_baseline'] = u if isinstance(u, type(None)) or isinstance(u, Exception): # Tweepy error, likely due to a private or invalid handle or (possibly) rate limit error error_dict = {'error': 'invalid', 'error_string': str(u)} self.participant.vars['handles'][ts] = error_dict if isinstance(self.player.error_log, type(None)): self.player.error_log = '' self.player.error_log += ';' + json.dumps(error_dict) return 'There was an error with your Twitter handle. Please confirm you entered your handle correctly.' if u['most_recent']['data']['protected']: self.participant.vars['handles'][ts] = {'error': 'protected'} return 'It looks like you entered a Twitter handle for a protected account, unfortunately only public accounts are eligible for this Experiment.' def before_next_page(self): # log session configs data = self.session.config data = dict((el, data[el]) for el in data if el not in ['participation_fee']) # data = dict((el, data[el]) for el in ) data['log_type'] = 'session_config' self.participant.vars['session_config'] = data self.player.live_handler(data) def is_displayed(self): if 'public_treatment' not in self.participant.vars or 'peer_treatment' not in self.participant.vars: self.run_randomization() return True def run_randomization(self): seed = string2seed(self.participant.__dict__['code']) self.participant.vars['seed'] = seed rnd = np.random.default_rng(seed=seed) self.participant.vars['public_treatment'] = rnd.random() < self.session.config['public_treatment_share'] self.participant.vars['placebo_treatment'] = (not self.participant.vars['public_treatment']) and ( rnd.random() < self.session.config['placebo_treatment_share']) self.participant.vars['peer_treatment'] = rnd.random() < self.session.config['peer_treatment_share'] self.participant.vars['show_summary_statistic'] = rnd.random() < 2 self.participant.vars['recommendations_page_reminder'] = rnd.random() < 10 self.participant.vars['bonus_lottery_amount'] = rnd.choice([100, 200]) # now draw recommendation randomizations recs_balanced = rnd.random() < self.session.config['recommendations_balanced_share'] random_draw = rnd.random() pop_share = self.session.config['recommendations_popularity_share'] personalized_share = self.session.config['recommendations_personalized_share'] assert pop_share + personalized_share <= 1 if random_draw < pop_share: rec_type = 'popular' elif random_draw < pop_share + personalized_share: rec_type = 'personalized' else: rec_type = 'random' self.participant.vars['recommendations_balanced'] = recs_balanced self.participant.vars['recommendations_type'] = rec_type if isinstance(self.player.log, type(None)): self.player.log = '' self.player.log += ';' + json.dumps({ 'log_type': 'randomization', 'public_treatment': self.participant.vars['public_treatment'], 'placebo_treatment': self.participant.vars['placebo_treatment'], 'peer_treatment': self.participant.vars['peer_treatment'], 'recommendations_balanced': recs_balanced, 'recommendations_type': rec_type }) class SectionI(Page): form_model = 'player' live_method = 'live_handler' form_fields = ['yearBirth', 'gender', 'education', 'ethnicity', 'ideology', 'ideologyTwitterFollowers', 'ideologyTwitterFollow', 'ideologyNews', 'ideologyTwitterFollowersNews', 'ideologyTwitterFollowNews', # 'timeFamily', 'timeTwitter', 'timeSocialMedia', 'timeNews', 'thermometerDemocratic', 'thermometerRepublican', 'thermometerBiden', 'thermometerTrump', 'trueBidenCovid', 'trueBeatty', 'trueMerkel', 'trueShooting', 'followsPolitics', 'voteLikely'] def is_displayed(self): handle = self.participant.vars['twitter_handle'] if handle.lower() in ['alex_moehring', 'candresmolina']: print('Setting optional') self.participant.vars['optional_treatment'] = True else: self.participant.vars['optional_treatment'] = np.random.rand() < 0 # setting optional to 0 for now optional_treatment = self.participant.vars['optional_treatment'] return not optional_treatment class SectionII(Page): form_model = 'player' live_method = 'live_handler' form_fields = ['closeParty', 'thermometerDemocratic', 'thermometerRepublican', 'thermometerBiden', 'thermometerTrump', 'trueBidenCovid', 'trueBidenFacebook', 'trueBeatty', 'trueMerkel', 'trueShooting', 'followsPolitics', 'voteLikely'] def is_displayed(self): optional_treatment = self.participant.vars['optional_treatment'] return not optional_treatment page_sequence = [Consent, SectionI]