def push_attached_pictures_at_inaturalist(self, access_token, user_agent): if self.inaturalist_id: for picture in self.pictures.all(): add_photo_to_observation(observation_id=self.inaturalist_id, file_object=picture.image.read(), access_token=access_token, user_agent=user_agent)
def update_test_obs(test_obs_id, token): response = add_photo_to_observation( test_obs_id, photo=SAMPLE_PHOTO, access_token=token, ) photo_id = response.get("photo").get("id") assert photo_id print("Added photo to observation: {}".format(photo_id)) # pprint(response, indent=2) response = update_observation( test_obs_id, geoprivacy="obscured", ignore_photos=True, access_token=token, ) new_geoprivacy = response[0]["geoprivacy"] assert new_geoprivacy == "obscured" print("Updated observation") # pprint(response, indent=2) response = put_observation_field_values( observation_id=test_obs_id, observation_field_id=297, value=2, access_token=token, ) print("Added observation field value:") pprint(response, indent=2)
def upload_obs(obs: Observation, token: str): logger.debug('upload_obs()') #TODO: Give the observation class a method to generate this JSON params = { 'observation': { 'taxon_id': obs.taxon_id, 'species_guess': obs.taxon_name, 'observed_on_string': str(obs.observed_on), 'time_zone': obs.tzone, 'description': obs.comment, 'tag_list': obs.tags, 'latitude': obs.coordinates[0], 'longitude': obs.coordinates[1], 'positional_accuracy': obs.geotag_accuracy, # meters, 'geoprivacy': obs.geotag_privacy, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } try: logger.info('Uploading observation for taxon {0}'.format(obs.taxon_id)) r = create_observations(params=params, access_token=token) obs.inat_id = r[0]['id'] for file in obs.photos: r = add_photo_to_observation(observation_id=obs.inat_id, file_object=open(file, 'rb'), access_token=token) except HTTPError as ex: obs.inat_result = 'Error creating observation: {0}'.format(ex) logger.error('Bad result from iNaturalist API, skipping this one') logger.exception(ex) except Exception as ex: raise else: logger.info('Success') obs.inat_result = 'ok'
def test_add_photo_to_observation(requests_mock): requests_mock.post( urljoin(INAT_BASE_URL, "observation_photos"), json=load_sample_data("add_photo_to_observation.json"), status_code=200, ) response = add_photo_to_observation(1234, BytesIO(), access_token="token") assert response["id"] == 1234 assert response["created_at"] == "2020-09-24T21:06:16.964-05:00" assert response["photo"]["native_username"] == "username"
time_zone, 'description': 'This is a test upload', 'tag_list': '', 'latitude': coordinates[0], 'longitude': coordinates[1], 'positional_accuracy': 50, # meters, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } r = create_observations(params=params, access_token=token) new_observation_id = r[0]['id'] from pyinaturalist.rest_api import add_photo_to_observation r = add_photo_to_observation(observation_id=new_observation_id, file_object=open(file, 'rb'), access_token=token) print("Program complete")
def upload_folder_multiple(species_folder, folder, uploaded_folder, time_zone, accuracy, user, passw, app, secret): # Makes a list of all files in the folder inside element 2 of a tuple for file in os.walk(folder): if file[0] == folder: files = file # Creates list of all the file paths for every file in the folder. file_paths = [] for file in files[2]: # All files are in files[2] file_path = files[0] + file # files[0] has the path to the folder file_paths.append(file_path) # Makes a big list of paths # This is getting a token to allow photos to be uploaded. token = get_access_token(username=user, password=passw, app_id=app, app_secret=secret) # This goes to every file, checks if it is a jpg, gets the gps coordinates, # get the time, and uploads it to iNaturalist. jpgs = [] for file in file_paths: if file[-3:].lower() == 'jpg': jpgs.append(file) try: img = PIL.Image.open(jpgs[0]) coordinates = get_lat_long(img) img.close() except: coordinates = 'No Coordinates' try: date_time = get_date(file) img.close() except: date_time = 'No Date or Time' [species, taxon] = get_taxon(species_folder) print(species) # print(coordinates) # print(date_time) # print(' the taxon is ' + str(taxon)) params = { 'observation': { 'taxon_id': taxon, 'species_guess': species, 'observed_on_string': date_time, 'time_zone': time_zone, 'description': '', 'tag_list': '', 'latitude': coordinates[0], 'longitude': coordinates[1], 'positional_accuracy': int(accuracy), # meters, 'observation_field_values_attributes': [{ 'observation_field_id': '', 'value': '' }], }, } r = create_observations(params=params, access_token=token) new_observation_id = r[0]['id'] print('Uploaded as observation #' + str(new_observation_id)) print('Uploading photos') for file in jpgs: print('uploading ' + str(file) + ' TO ' + str(new_observation_id)) r = add_photo_to_observation(observation_id=new_observation_id, file_object=open(file, 'rb'), access_token=token) folder_name = os.path.split(folder) folder1_name = os.path.split(folder_name[0]) folder2_name = os.path.split(folder1_name[0]) new_species_folder = uploaded_folder + folder2_name[1] + '/' destination = new_species_folder + folder1_name[1] if new_observation_id: try: os.mkdir(new_species_folder) except: pass try: shutil.move(folder, destination) except: print('failed file move') pass
def inaturalist_api(): json_data = json.loads(request.data) print(json_data) utc_key = json_data['utc_key'] print(f'utc_key: {utc_key}') if utc_key is None: return print(f'key: {utc_key}') conn = sqlite3.connect(DB_PATH, timeout=15) query = '''SELECT datetime, file_name, prediction, true_label, inaturalist_id FROM results WHERE utc_datetime = ? LIMIT 1;''' c = conn.cursor() c.execute(query, (utc_key, )) row = c.fetchone() if row is None: return else: obs_timestamp = row[0] img_fn = row[1] pred_label = row[2] true_label = row[3] existing_inat_id = row[4] if true_label is not None: obs_label = true_label else: obs_label = pred_label # Get a token for the inaturalist API token = get_access_token( username=INAT_USERNAME, password=INAT_PASSWORD, app_id=INAT_APP_ID, app_secret=INAT_APP_SECRET, ) obs_file_name = f'{DATA_DIR}/imgs/{img_fn}' # Upload the observation to iNaturalist if existing_inat_id is None: # Check if there's an existing inat id within 5 minutes of this image # upload this image to that observation if so. window_timestamp = dt.datetime.fromisoformat(utc_key) - dt.timedelta( minutes=10) window_timestamp = window_timestamp.strftime(dt_fmt) query = '''SELECT inaturalist_id FROM results WHERE utc_datetime <= :utc_dt AND utc_datetime >= :prev_dt AND inaturalist_id IS NOT NULL AND (true_label = :lab OR (true_label IS NULL AND prediction = :lab)) ORDER BY utc_datetime DESC LIMIT 1;''' c.execute(query, { 'utc_dt': utc_key, 'prev_dt': window_timestamp, 'lab': obs_label }) row = c.fetchone() if row is None or row[0] is None: response = create_observation( taxon_id=species_map[obs_label]['taxa_id'], observed_on_string=obs_timestamp, time_zone='Mountain Time (US & Canada)', description= 'Birb Cam image upload: https://github.com/evjrob/birbcam', tag_list=f'{obs_label}, Canada', latitude=INAT_LATITUDE, longitude=INAT_LONGITUDE, positional_accuracy=INAT_POSITIONAL_ACCURACY, # meters, access_token=token, ) inat_observation_id = response[0]['id'] print( f'No iNaturalist id found in previous ten minutes, creating new row with id {inat_observation_id}.' ) else: inat_observation_id = row[0] print( f'Found iNaturalist id in previous ten minutes, adding to id {inat_observation_id}.' ) # Upload the image captured r = add_photo_to_observation( inat_observation_id, access_token=token, photo=obs_file_name, ) # Update the row in the database with the inaturalist id c.execute("UPDATE results SET inaturalist_id=? WHERE utc_datetime=?;", (inat_observation_id, utc_key)) else: # This image had already been uploaded, we do not want to upload it again inat_observation_id = existing_inat_id print( f'Found existing iNaturalist id {inat_observation_id} for row, skipping.' ) conn.commit() conn.close() return jsonify({'inat_id': inat_observation_id})