Я новичок в облачных платформах. Я пытаюсь создать облачную функцию в облаке Google с триггером 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, просто пример)
Несмотря на это, использование функции тестирования в интерфейсе Google Cloud по-прежнему работает должным образом даже после развертывания, когда я использую аргументы на изображении выше {'url': 'www.someimage.com'}
Код облачной функции следующий:
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 Testing? Неправильно ли использовать ?url="..." в адресной строке? Есть ли другой способ получить ожидаемые результаты, например, используя завиток или пакет запросов Python?






Неправильно ли использовать ?url="..." в адресной строке?
Да, это неправильно для вашего кода.
Ваше тестирование отправляет в функцию полезную нагрузку JSON, а ваш код анализирует эту полезную нагрузку с помощью request.get_json(silent=True). Это не то же самое, что использование параметра строки запроса URL.
Если вы хотите принять параметр строки запроса URL, прочитайте это:
Для этого вам следует использовать request.args.get('url').
Если вы хотите продолжать использовать полезную нагрузку JSON в запросе, вы не сможете легко работать в браузере, поскольку он не предоставит простой способ ввода JSON, который вы хотите отправить. Но вы можете использовать Curl, чтобы указать полезную нагрузку JSON, аналогичную той, которая используется в вашем существующем тестировании:
Ага, понятно. Как вы и сказали, я использовал cURL, и он действительно работает! Я также развернул новую облачную функцию, которая вместо этого использует request.args.get('url'), и это именно то, что я пытался (и не смог) сделать. Большое спасибо! Точная команда cURL, которая сработала для меня, была Curl -X POST myprojectandfunction/function-1 -H "Content-Type: application/json" -d '{"url": " Zooplus.pt/magazine/wp -content/uploads/2021/10/…"}'