Отображение изображения из облачного хранилища Google на веб-сайте flask, размещенном в Google Cloud, с использованием python 3

#python #html #google-app-engine #flask #google-cloud-storage

# #python #HTML #google-app-engine #flask #google-облачное хранилище

Вопрос:

Я пытаюсь создать веб-сайт, который принимает ввод текста, генерирует изображение, а затем отображает это изображение обратно в html.

Это отлично работает, записывая изображение в статический каталог, когда у меня есть локальная тестовая реализация, но когда я нажимаю на Google Cloud, мне не разрешается записывать в каталог. Я выяснил, как сохранить изображение в моем хранилище Google Cloud, но теперь я не могу вернуть изображение для отображения в шаблоне html.

Я использую Flask и python 3.7

Вот что я делаю:

 from flask import Flask, render_template, request, send_file
import time
#import cloudstorage
import io, os
from google.cloud import storage
import tempfile

import functions

app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0

@app.route("/")
def home():
    return render_template("home_css.html")
    
@app.route('/', methods=['POST'])
def my_form_post():
    text = request.form['text']
    URL = functions.main(text)
    print(URL)
    return render_template("return_img_css.html", picture_path = URL, screen_name = text)
 

Где часть функций содержит блок, который УСПЕШНО СОХРАНЯЕТ изображение для возврата URL-адреса изображения:

 def make_plot():
    ....
    # NEED to SAVE THE IMAGE TO GOOGLE CLOUD
    client = storage.Client(project='meytweets')
    bucket = client.bucket('meytweets.appspot.com')
    savename =  'static/'  screen_name  '_network.png'
    blob = bucket.blob(savename)
    # temporarily save image to buffer
    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    
    # upload buffer contents to gcs
    blob.upload_from_string(
        buf.getvalue(),
        content_type='image/png')
    buf.close()
    return blob.public_url
 

Где этот URL-адрес обычно выглядит так:
https://storage.googleapis.com/meytweets.appspot.com/static/twitter_network.png

И шаблон HTML выглядит так:

 {% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Network for Twitter User: {{ screen_name }} {% endblock %}</h1>    
    <img src="{{ picture_path }}" >
{% endblock %}
 

Вот app.yaml:

 runtime: python37

env_variables:
    CLOUD_STORAGE_BUCKET: meytweets.appspot.com

handlers:
- url: /static
  static_dir: public
- url: /.*
  script: auto
  
 

Как я писал выше, изображение сохраняется в моем облачном хранилище Google, но затем я не могу вернуть его для отображения в html:
скриншот

Я открыт для других стратегий, которые не записываются в Google Cloud, все, что работает для отображения изображения, которое я создаю в matplotlib, меня устраивает.

Ответ №1:

При запуске приложения в бессерверной среде /tmp доступен для записи только каталог. Вы не можете изменить содержимое другого каталога, например /static . Кроме того, /tmp каталог представляет собой файловую систему в памяти, и, таким образом, когда экземпляр уничтожается, все /tmp они исчезают.

Теперь вы можете попробовать установить /tmp в обработчиках. Я никогда не тестировал, не уверен в результате и его согласованности.

Другое решение — сохранить изображение в облачном хранилище Google и, наконец, сгенерировать ваш HTML с изображением в облачном хранилище Google, разумеется, общедоступном.

Комментарии:

1. похоже, вы предлагаете мне попытаться сохранить изображение в / tmp вместо этого, а затем отправить изображение из temp в HTML? У меня создалось впечатление, что я могу обслуживать только из «статического», но я могу использовать свое хранилище Google Cloud Storage как статическое, используя обработчик: « обработчики: — url: / static static_dir: public

2. Должно работать обслуживание из / tmp в HTML (я никогда не пробовал, но по замыслу это не должно работать). Решение для облачного хранилища лучше, но вам нужно сделать ваше хранилище общедоступным, чтобы позволить любому получить к нему доступ.

Ответ №2:

Прошло некоторое время с тех пор, как был задан этот вопрос, но мне нужно было сделать то же самое, и он заработал. Я сохраняю изображения в хранилище объектов Google и вставляю их в шаблоны jinja2 в виде данных в кодировке base64 в тегах img.

Маршрут:

 @app.route("/view/<string:blob_name>")
def view(blob_name):
    bucket = get_bucket()
    blob = bucket.get_blob(blob_name)
    content = blob.download_as_bytes()
    image = base64.b64encode(content).decode("utf-8")
    return render_template('view.html', content_type=blob.content_type, image=image)
 

Шаблон:

   <body>
    <h1>Image:</h1>
    <img src="data:{{ content_type }};base64,{{ image }}" />
  </body>
 

Это решение работает, если flask работает в бессерверной среде, где вы не можете создавать временные файлы и не хотите делать данные общедоступными.