Google Cloud 中的云功能在测试中有效,但在部署后无效

问题描述 投票:0回答:1

对于云平台,我是一个初学者。我正在尝试在谷歌云中创建一个带有 HTTP 触发器的云函数,其中给定图像 url 作为参数,它应该下载它并获取我之前在 Tensorflow 中训练的图像分类模型的结果,并且我将其与包含可能的模型输出的文本文件一起保存在一个存储桶中。 该模型运行良好,就像我在 Google Cloud 界面中使用测试功能时所希望的那样,如下所示:Cloud Function working as intended, receiving an image url and outputting classification results

但是,在实际部署云功能后,我无法让它像使用浏览器时那样工作......如果我在地址中写入这样的内容,它总是会产生 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包?

python http google-cloud-platform google-cloud-functions cloud
1个回答
0
投票

地址栏中使用 ?url="..." 是否错误?

是的,您的代码是错误的。

您的测试正在向函数发送 JSON 有效负载,并且您的代码正在使用

request.get_json(silent=True)
解析该有效负载。这与使用 URL 查询字符串参数不同。

如果您想接受 URL 查询字符串参数,请阅读以下内容:

您应该使用

request.args.get('url')
来实现这一点。

如果您想在请求中继续使用 JSON 有效负载,您将无法在浏览器中轻松完成此操作。但您可以使用curl 指定与现有测试中的负载类似的JSON 负载:

© www.soinside.com 2019 - 2024. All rights reserved.