对于云平台,我是一个初学者。我正在尝试在谷歌云中创建一个带有 HTTP 触发器的云函数,其中给定图像 url 作为参数,它应该下载它并获取我之前在 Tensorflow 中训练的图像分类模型的结果,并且我将其与包含可能的模型输出的文本文件一起保存在一个存储桶中。 该模型运行良好,就像我在 Google Cloud 界面中使用测试功能时所希望的那样,如下所示:
但是,在实际部署云功能后,我无法让它像使用浏览器时那样工作......如果我在地址中写入这样的内容,它总是会产生 500 内部错误我的浏览器栏: https://myprojectandfunction.net/function-1?url=https://www.zooplus.pt/magazine/wp-content/uploads/2021/10/gatos_apartamento_1.jpeg(这不是实际的云函数网址,只是一个例子)
尽管如此,当我使用上图中的参数 {'url': 'www.someimage.com'} 时,即使在部署后,使用 Google Cloud Interface 中的测试功能仍然可以按预期工作
云函数的代码是这样的:
import functions_framework
import requests
import os
from PIL import Image
import tensorflow as tf
import numpy as np
from google.cloud import storage
client = storage.Client()
bucket_url = 'justsomebucketname'
model_file = 'model.tflite'
label_file = 'dict.txt'
bucket = client.get_bucket(bucket_url)
blob_model = bucket.blob(model_file)
blob_label = bucket.blob(label_file)
blob_model.download_to_filename("model.tflite")
blob_label.download_to_filename("dict.txt") # Getting the model and labels I will need from my bucket
# This class is just the model I need for classification
class Model:
def __init__(self, model_file, dict_file):
with open(dict_file, 'r') as f:
self.labels = [line.strip().replace('_', ' ') for line in f.readlines()]
self.interpreter = tf.lite.Interpreter(model_path=model_file)
self.interpreter.allocate_tensors()
self.input_details = self.interpreter.get_input_details()
self.output_details = self.interpreter.get_output_details()
self.floating_model = self.input_details[0]['dtype'] == np.float32
self.height = self.input_details[0]['shape'][1]
self.width = self.input_details[0]['shape'][2]
def classify(self, file, min_confidence):
with Image.open(file).convert('RGB').resize((self.width, self.height)) as img:
input_data = np.expand_dims(img, axis=0)
if self.floating_model:
input_data = (np.float32(input_data) - 127.5) / 127.5
self.interpreter.set_tensor(self.input_details[0]['index'], input_data)
self.interpreter.invoke()
output_data = self.interpreter.get_tensor(self.output_details[0]['index'])
model_results = np.squeeze(output_data)
top_categories = model_results.argsort()[::-1]
results = []
for i in top_categories:
if self.floating_model:
confidence = float(model_results[i])
else:
confidence = float(model_results[i] / 255.0)
if min_confidence != None and confidence < min_confidence:
break
results.append(dict(label=self.labels[i], confidence='%.2f'%confidence))
return results
# Here I just edited the basic template for HTTP cloud functions, given by google cloud
@functions_framework.http
def hello_http(request):
"""HTTP Cloud Function.
Args:
request (flask.Request): The request object.
<https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
Returns:
The response text, or any set of values that can be turned into a
Response object using `make_response`
<https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
"""
request_json = request.get_json(silent=True)
request_args = request.args
if request_json and 'url' in request_json:
url = request_json['url'] # extract the url from the request
response = requests.get(url) # get the image data from the url
with open('image.jpg', 'wb') as imagem:
imagem.write(response.content) # create a jpg file with the data
tf_classifier = Model(model_file, label_file) # instantiate the classifier
results = tf_classifier.classify('image.jpg', min_confidence=0.01) # get the model results
string = "According to the model, your image corresponds to, in descending order of confidence:\n"
for r in results:
string += f"\t {r['label']}, with a confidence of {r['confidence']};\n" # Generate a sentence that summarizes the classification results
elif request_args and 'url' in request_args:
url = request_json['url']
response = requests.get(url)
with open('image.jpg', 'wb') as imagem:
imagem.write(response.content)
tf_classifier = Model(model_file, label_file)
results = tf_classifier.classify('image.jpg', min_confidence=0.01)
string = "According to the model, your image corresponds to, in descending order of confidence:\n"
for r in results:
string += f"\t {r['label']}, with a confidence of {r['confidence']};\n"
else:
string = 'You didn't supply a url... Try again!'
return string
使用浏览器时,根据 Google Cloud 中的日志,500 内部错误来自 TypeError,其中 url = request_json['url'] 是 None Type 并且不可下标。但在测试中并没有发生这种情况...
我需要提出什么请求才能获得与 Google Cloud 测试界面中相同的结果?在地址栏中使用 ?url="..." 是否错误?有没有其他方法可以获得预期的结果,例如使用curl或python requests包?
地址栏中使用 ?url="..." 是否错误?
是的,您的代码是错误的。
您的测试正在向函数发送 JSON 有效负载,并且您的代码正在使用
request.get_json(silent=True)
解析该有效负载。这与使用 URL 查询字符串参数不同。
如果您想接受 URL 查询字符串参数,请阅读以下内容:
您应该使用
request.args.get('url')
来实现这一点。
如果您想在请求中继续使用 JSON 有效负载,您将无法在浏览器中轻松完成此操作。但您可以使用curl 指定与现有测试中的负载类似的JSON 负载: