How to use Ruby to send image to a deployed Sagemaker endpoint running a TensorFlow/Keras CNN? - ruby

I have trained a CNN using Tensorflow/Keras and successfully deployed it to Sagemaker using the saved_model format. It answers pings and the dashboard shows it is running.
I now need to be able to send it images and get back inferences. I have already successfully deployed an ANN to Sagemaker and gotten predictions back, so most of the "plumbing" is already working.
The Ruby performing the request is as follows:
def predict
sagemaker = Aws::SageMakerRuntime::Client.new(
access_key_id: Settings.sagemaker_key_id,
secret_access_key: Settings.sagemaker_secret,
region: Settings.sagemaker_aws_region
)
response = sagemaker.invoke_endpoint(endpoint_name: Settings.sagemaker_endpoint_name,
content_type: 'application/x-image',
body: File.open('developer/ai/caox_test_128.jpg', 'rb'))
return response[:body].string
end
(For now, I simply hardcoded a known file for testing.)
When I fire this, I get back this error: Aws::SageMakerRuntime::Errors::ModelError: Received client error (400) from model with message "{ "error": "JSON Parse error: Invalid value. at offset: 0" }"
It's almost as if the model is expecting more in the body than just the image, but I can't tell what. AWS's documentation has an example for Python using boto:
import boto3
import json
endpoint = '<insert name of your endpoint here>'
runtime = boto3.Session().client('sagemaker-runtime')
# Read image into memory
with open(image, 'rb') as f:
payload = f.read()
# Send image via InvokeEndpoint API
response = runtime.invoke_endpoint(EndpointName=endpoint, ContentType='application/x-image', Body=payload)
# Unpack response
result = json.loads(response['Body'].read().decode())
As far as I can tell, they are simply opening a file and sending it directly to sagemaker with no additional pre-processing. And, insofar as I can tell, I'm doing exactly what they are doing in Ruby, just using 'aws-sdk'.
I've looked through Amazon's documentation, and for examples on Google, but there is scant mention of doing anything special before sending the file, so I'm scratching my head.
What else do I need to consider when sending a file to a Sagemaker endpoint running a TensorFlow/Keras CNN to get it to respond with a prediction?

Related

Ruby YouTube Data API v3 insert caption always returns error

I am trying to use the Ruby SDK to upload videos to YouTube automatically. Inserting a video, deleting a video, and setting the thumbnail for a video works fine, but for some reason trying to add captions results in an invalid metadata client error regardless of the parameters I use.
I wrote code based on the documentation and code samples in other languages (I can't find any examples of doing this in Ruby with the current gem). I am using the google-apis-youtube_v3 gem, version 0.22.0.
Here is the relevant part of my code (assuming I have uploaded a video with id 'XYZ123'):
require 'googleauth'
require 'googleauth/stores/file_token_store'
require 'google-apis-youtube_v3'
def authorize [... auth code omitted ...] end
def get_service
service = Google::Apis::YoutubeV3::YouTubeService.new
service.key = API_KEY
service.client_options.application_name = APPLICATION_NAME
service.authorization = authorize
service
end
body = {
"snippet": {
"videoId": 'XYZ123',
"language": 'en',
"name": 'English'
}
}
s = get_service
s.insert_caption('snippet', body, upload_source: '/path/to/my-captions.vtt')
I have tried many different combinations, but the result is always the same:
Google::Apis::ClientError: invalidMetadata: The request contains invalid metadata values, which prevent the track from being created. Confirm that the request specifies valid values for the snippet.language, snippet.name, and snippet.videoId properties. The snippet.isDraft property can also be included, but it is not required. status_code: 400
It seems that there really is not much choice for the language and video ID values, and there is nothing remarkable about naming the captions as "English". I am really at a loss as to what could be wrong with the values I am passing in.
Incidentally, I get exactly the same response even if I just pass in nil as the body.
I looked at the OVERVIEW.md file included with the google-apis-youtube_v3 gem, and it referred to the Google simple REST client Usage Guide, which in turn mentions that most object properties do not use camel case (which is what the underlying JSON representation uses). Instead, in most cases properties must be sent using Ruby's "snake_case" convention.
Thus it turns out that the snippet should specify video_id and not videoId.
That seems to have let the request go through, so this resolves this issue.
The response I'm getting now has a status of "failed" and a failure reason of "processingFailed", but that may be the subject of another question if I can't figure it out.

Do AutoMl predictions not work when uploaded into Google Cloud Functions

Im writing code that makes a prediction based on a trained AutoMl multi-label Classifier. The function works if I run it locally, however, as soon as i upload the same code to Cloud Functions on GCP (a process that i know usually works) it provides me with this error
TypeError: predict() takes from 1 to 2 positional arguments but 4 were given
Here is a sample of my code, taken straight from the AutoMl documentation with some slight adjustments.
def get_sentiment(content):
"""
Returns a google cloud platform payload class containing the sentiment score given by our NLP sentiment analyser.
:param content: STRING (UTF-8 encoded, ASCII)
:return: <class 'google.cloud.automl.types.PredictResponse'>
"""
options = ClientOptions(api_endpoint='automl.googleapis.com')
prediction_client = automl_v1beta1.PredictionServiceClient(client_options=options)
name = model_sentiment
payload = {'text_snippet': {'content': content, 'mime_type': 'text/plain'}}
params = {}
request = prediction_client.predict(name, payload, params)
return request
I have tried removing the params variable from prediction and replacing payload with content the only change is that I get the error:
TypeError: predict() takes from 1 to 2 positional arguments but 3 were given
Additionally, I have replaced automl_v1beta1 with automl and automl_v1. and again while both work locally they do not work on Google Cloud.
Thank you for any advice or help
Update, Apparently there are some bugs in the latest version of AutoML and the error was fixed by running the code on a previous version of it. Specifically in my case v0.9.0

how can I get ALL records from route53?

how can I get ALL records from route53?
referring code snippet here, which seemed to work for someone, however not clear to me: https://github.com/aws/aws-sdk-ruby/issues/620
Trying to get all (I have about ~7000 records) via resource record sets but can't seem to get the pagination to work with list_resource_record_sets. Here's what I have:
route53 = Aws::Route53::Client.new
response = route53.list_resource_record_sets({
start_record_name: fqdn(name),
start_record_type: type,
max_items: 100, # fyi - aws api maximum is 100 so we'll need to page
})
response.last_page?
response = response.next_page until response.last_page?
I verified I'm hooked into right region, I see the record I'm trying to get (so I can delete later) in aws console, but can't seem to get it through the api. I used this: https://github.com/aws/aws-sdk-ruby/issues/620 as a starting point.
Any ideas on what I'm doing wrong? Or is there an easier way, perhaps another method in the api I'm not finding, for me to get just the record I need given the hosted_zone_id, type and name?
The issue you linked is for the Ruby AWS SDK v2, but the latest is v3. It also looks like things may have changed around a bit since 2014, as I'm not seeing the #next_page or #last_page? methods in the v2 API or the v3 API.
Consider using the #next_record_name and #next_record_type from the response when #is_truncated is true. That's more consistent with how other paginations work in the Ruby AWS SDK, such as with DynamoDB scans for example.
Something like the following should work (though I don't have an AWS account with records to test it out):
route53 = Aws::Route53::Client.new
hosted_zone = ? # Required field according to the API docs
next_name = fqdn(name)
next_type = type
loop do
response = route53.list_resource_record_sets(
hosted_zone_id: hosted_zone,
start_record_name: next_name,
start_record_type: next_type,
max_items: 100, # fyi - aws api maximum is 100 so we'll need to page
)
records = response.resource_record_sets
# Break here if you find the record you want
# Also break if we've run out of pages
break unless response.is_truncated
next_name = response.next_record_name
next_type = response.next_record_type
end

Convert Video to text(transcript) by google cloud speech to text with Rails Application

Working on a WebAppon Ruby on Rails.
I want to get subtitle for Pre recorded video and also for new videos going to record.
I have implemented the gem 'google-cloud-speech'.
But now I'm not able to get text for my video. I get a suggestion from Google Cloud API doc to add model but when I add model: 'video' to configuration, it says there is no such field model in initialization map entry.
My code without adding model is as per below.
speech_client = Google::Cloud::Speech.new
config ={ encoding: :LINEAR16,
sample_rate_hertz: 16000,
language_code: "en-US",
}
audio = { uri: #uri }
response = speech.recognize config, audio
which is giving me error message like below.
Google::Gax::RetryError: GaxError Exception occurred in retry method that was not classified as transient, caused by 3:Request contains an invalid argument.
from /Users/hiren/.rvm/gems/ruby-2.5.1#Snip/gems/google-gax-1.3.0/lib/google/gax/api_callable.rb:369:in `rescue in block in retryable'
Any help is appreciated.
Thanks
Regarding the model issue, this might be due to that the video model is not available yet for Ruby V1 API version as this feature it's part of the v1p1beta1 version.
Regarding your code issue, I just did the example shown here successfully. It would be helpful if you attach your full code as the documented code works well.

Google Server to Server OAuth Error

I'm trying to connect my server to Google's API but I keep getting the following error.
google.auth.exceptions.RefreshError: ('invalid_scope: h is not a valid audience string.', u'{\n "error" : "invalid_scope",\n "error_description" : "h is not a valid audience string."\n}')
I've looked around but I just can't seem to get why google's supplied code is giving me that error. I think it's a problem with my service.json, but I can't pinpoint what it is.
This is the code, which is pretty much swiped from Google with very limited changes.
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
SERVICE_ACCOUNT_FILE = 'service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive = googleapiclient.discovery.build('drive', 'v3', credentials=credentials)
response = drive.files().list(
pageSize=10,fields="nextPageToken, files(id, name)").execute()
print(response)
What I'm looking to do is automatically download a spreadsheet to local using Google's API maybe once an hour without user verification.
I'm having this error.
It looks like scopes is expected to be iterable, so when a single string is given, the library processes each letter separately (the first being 'h').
Try changing line 4 to add brackets:
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']

Resources