Open lucksp opened 1 year ago
Hi @danielbankhead did you figure out the correct format for this? facing the same issue and this library typing and docs are lacking a lot of info.
Looking at the autogenerated sample, the request looks correct:
I don’t work on this product, but someone should chime in soon.
meanwhile...
const [response] = await this.predictionClient.predict(request);
const prediction = helpers.fromValue(response.predictions[0] as any);
const metadata = helpers.fromValue(response.metadata as any);
I'm running into the same issue, I was able to successfully retrieve a prediction by using the fetch API but am unable to translate this to the SDK package (so that I don't have to add the complexity of refreshing access tokens). For reference, here's the fetch API version:
import { convertImageToBase64 } from "@/lib/utils";
const {
GCP_ACCESS_TOKEN,
GCP_LOCATION,
GCP_PROJECT_ID,
GCP_PREDICTION_ENDPOINT_ID,
} = process.env;
export async function POST(request: Request) {
try {
const { imageUrl } = await request.json();
const base64Image = await convertImageToBase64(imageUrl);
const apiRoute = `https://${GCP_LOCATION}-aiplatform.googleapis.com/v1/projects/${GCP_PROJECT_ID}/locations/${GCP_LOCATION}/endpoints/${GCP_PREDICTION_ENDPOINT_ID}:predict`;
const payload = {
instances: [
{
content: base64Image,
},
],
parameters: {
confidenceThreshold: 0.5,
maxPredictions: 5,
},
};
const response = await fetch(apiRoute, {
method: "POST",
headers: {
Authorization: `Bearer ${GCP_ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const data = await response.json();
return new Response(
JSON.stringify({
predition: data.predictions && data.predictions[0]?.displayNames[0],
}),
{
headers: { "Content-Type": "application/json" },
}
);
} catch (error: any) {
return new Response(
JSON.stringify({
error: error?.message || "Server error",
}),
{
headers: { "Content-Type": "application/json" },
status: 500,
}
);
}
}
And here's the attempt at the SDK:
import aiPlatform from "@google-cloud/aiplatform";
import { convertImageToBase64 } from "@/lib/utils";
const {
GCP_PROJECT_ID,
GCP_CLIENT_EMAIL,
GCP_PRIVATE_KEY,
GCP_LOCATION,
GCP_PREDICTION_ENDPOINT_ID,
} = process.env;
const predictionServiceClient = new aiPlatform.v1.PredictionServiceClient({
projectId: GCP_PROJECT_ID!,
credentials: {
client_email: GCP_CLIENT_EMAIL!,
private_key: GCP_PRIVATE_KEY!,
},
apiEndpoint: `${GCP_LOCATION}-aiplatform.googleapis.com`,
});
export async function predictImage(imageUrl: string) {
const endpoint = `projects/${GCP_PROJECT_ID}/locations/${GCP_LOCATION}/endpoints/${GCP_PREDICTION_ENDPOINT_ID}`;
const base64Image = await convertImageToBase64(imageUrl);
const payload = {
endpoint,
instances: [
{
content: base64Image,
},
],
parameters: {
confidenceThreshold: 0.5,
maxPredictions: 5,
},
};
const response = await predictionServiceClient.predict(payload);
return response.predictions && response.predictions[0]?.displayNames[0];
}
I'm getting errors that await has no effect on this type of expression (when invoking predictionServiceClient.predict()) and the payload is throwing the following Typescript error:
Argument of type '{ endpoint: string; instances: { content: string; }[]; parameters: { confidenceThreshold: number; maxPredictions: number; }; }' is not assignable to parameter of type 'IPredictRequest'.
Types of property 'instances' are incompatible.
Type '{ content: string; }[]' is not assignable to type 'IValue[]'.
Type '{ content: string; }' has no properties in common with type 'IValue'.ts(2345)
I'm also getting the same error as @lucksp when trying to execute the function.
Apologies for the back-to-back posts! But implementing token refreshing was actually a breeze with the google-auth-library package. So I wanted to share an interim workaround until the predictionServiceClient is fixed; here's the full function that I'm using (error handling excluded for sake of simplicity):
import { GoogleAuth } from "google-auth-library";
const {
GCP_PROJECT_ID,
GCP_CLIENT_EMAIL,
GCP_PRIVATE_KEY,
GCP_LOCATION,
GCP_PREDICTION_ENDPOINT_ID,
} = process.env;
const googleAuth = new GoogleAuth({
projectId: GCP_PROJECT_ID!,
credentials: {
client_email: GCP_CLIENT_EMAIL!,
private_key: GCP_PRIVATE_KEY!,
},
scopes: ["https://www.googleapis.com/auth/cloud-platform"],
});
export async function predictImage(imageUrl: string) {
const base64Image = await convertImageToBase64(imageUrl);
const apiRoute = `https://${GCP_LOCATION}-aiplatform.googleapis.com/v1/projects/${GCP_PROJECT_ID}/locations/${GCP_LOCATION}/endpoints/${GCP_PREDICTION_ENDPOINT_ID}:predict`;
const payload = {
instances: [
{
content: base64Image,
},
],
parameters: {
confidenceThreshold: 0.5,
maxPredictions: 5,
},
};
const accessToken = await googleAuth.getAccessToken();
const response = await fetch(apiRoute, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const data = await response.json();
return data.predictions;
}
export async function convertImageToBase64(imageUrl: string): Promise<string> {
const response = await fetch(imageUrl);
const buffer = await response.arrayBuffer();
return btoa(
new Uint8Array(buffer).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
}
Hey folks, I'm waiting for someone more familiar with the product to get back to help everyone. In the meantime, perhaps the instances
value in the payload references an int ID of sorts; here's a sample:
For image classification, does this sample help? https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/main/ai-platform/snippets/predict-image-classification.js#L57-L60
(Note the helper to_value
method.)
Alternatively, you can build a protobuf.Value message directly, which are often deeply nested with number_value
, list_value
, etc. keys, https://protobuf.dev/reference/protobuf/google.protobuf/#value
For image classification, does this sample help? https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/main/ai-platform/snippets/predict-image-classification.js#L57-L60
(Note the helper
to_value
method.)Alternatively, you can build a protobuf.Value message directly, which are often deeply nested with
number_value
,list_value
, etc. keys, https://protobuf.dev/reference/protobuf/google.protobuf/#value
This is the example I was using but got errors when trying to import the { instance, params, prediction } found here: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/main/ai-platform/snippets/predict-image-classification.js#L31-L32
It was saying that they didn't exist
Looks like those imports refer to files here: https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-aiplatform/protos/google/cloud/aiplatform/v1/schema/predict
Could you confirm that they have been installed?
This is how it's work
const prompt = {
content: base64Image,
}
const instance = helpers.toValue(prompt);
const instances = [instance];
const parameter ={
confidenceThreshold: 0.5,
maxPredictions: 5,
};
const parameters = helpers.toValue(parameter);
const predictRequest = PredictRequest.fromObject({
endpoint,
instances,
parameters,
});
const [predictResult] = await predictClient.predict(predictRequest);
Hope it's help
@ryuzaki01 where are you importing PredictRequest from?
PredictRequest
import {google, google as googleAi} from "@google-cloud/aiplatform/build/protos/protos"; import PredictRequest = googleAi.cloud.aiplatform.v1.PredictRequest;
Environment details
"@google-cloud/aiplatform": "^2.14.0"
Steps to reproduce
Error from
predict
requesst:The
predict
method is typed as aIPredictRequest
:based on the error message
3 INVALID_ARGUMENT:
it seems like one of my arguments is incorrect? But which one? I am guessing theendpoint
being passed in? But what format should it be? the typing is juststring
with no other details. This table of codes doesn't help clarify either