Изображение не отображается после создания изображения AI и завершения ответа

Я возвращаюсь к разработке после многих лет бездействия, поэтому мои навыки довольно заржавели, и я заранее прошу прощения за любые неправильные проблемы с синтаксисом и форматированием.

В настоящее время я работаю над небольшим проектом веб-приложения, которое принимает текстовую подсказку и генерирует изображение с помощью Googles aivertex и Gemini.

Вот несколько фрагментов кода для ознакомления.

HTML-шаблон

<body>
    <h1>Turn your words into art!</h1>
    <p>Enter a description of the image you want to generate.</p>
    <form target = "_blank" id = "text-form" action = "/my_prompt" onsubmit = "dontredict('myindex.html')" method = "post">
        <label for = "text-input">Text Prompt:</label>
        <textarea id = "text-input" name = "text" rows = "5" placeholder = "e.g. A cat riding a bicycle on Mars"></textarea>
        <button type = "submit">Generate Image</button>
    </form>
    <div id = "image-container">
        {% if img_data %}
        <h1>Your generated image will appear here.</h1>
        <img id = "picture" style = "height: 300px;" src = "{{url_for('static',filename='my-output.png')}}">
        {% else %}
        <h1>Image will be render here...</h1>
        {% endif %}
    </div>
        <!--Jquery Cdn -->
        <script src = "https://code.jquery.com/jquery-3.5.1.js" integrity = "sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc = "
            crossorigin = "anonymous"></script>
        
        <script type = "text/javascript">
           function dontredict(dynamicUrl){ 
            $(document).on('submit', '#text-form', function (e) {
                e.preventDefault();
                console.info('button smashed');
                $.ajax({
                    type: 'POST',
                    url: '/my_prompt',
                    data: {
                        text: $("#text-input").val()
                    },
                    success: function () {
                        alert('saved');
                    }
                })
            });
        }
        </script>
</body>

Преобразование текста в изображение Python.py

def disp_image():
    if os.path.exists(output_file):
        im = Image.open("static/my-output.png")
        data = io.BytesIO()
        im.save(data, "PNG")
        encoded_img_data = base64.b64encode(data.getvalue())
        img_data=encoded_img_data.decode('utf-8')
        return render_template("myindex.html", img_data=img_data)
    #if os.path.exists(output_file):
            #return redirect(url_for('static/my-output.png'))

@app.route('/my_prompt', methods = ['POST'])
@cross_origin()
def imggen():
   print("inside gen")
   if request.method == 'POST':
      prompt = request.form.get("text")
      logger.info('%s This is the prompt: ', prompt)
      print(prompt); 
      print("after prompt") 
      model = ImageGenerationModel.from_pretrained("imagegeneration@006")
      images = model.generate_images(
        prompt=prompt,
        # Optional parameters
        number_of_images=1,
        language = "en",
        # You can't use a seed value and watermark at the same time.
        # add_watermark=False,
        # seed=100,
        aspect_ratio = "1:1",
        safety_filter_level = "block_some",
        person_generation = "allow_adult",
        )
      images[0].save(location=output_file, include_generation_parameters=False)
      print(f"Created output image using {len(images[0]._image_bytes)} bytes")
      print(disp_image())
      return disp_image()
       
   else:
        print("error")

Проблемы, с которыми я сталкиваюсь, заключаются в том, что когда текст публикуется и возвращается со сгенерированным изображением, он правильно сохраняется в папке статического изображения (с использованием flask и python), но он не отображается и не отображается на html-странице. Я также осознаю, что часть кода может быть избыточной. Дайте мне знать, что я делаю неправильно с точки зрения отображения изображения на реальной html-странице. Спасибо.

🤔 А знаете ли вы, что...
Python поддерживает динамическую типизацию, что облегчает разработку.


1
86
1

Ответ:

Решено

Когда вы используете $.ajax (или встроенный современный fetch() или более старый XMLHttpRequest())
тогда браузер не обновляет HTML. Это твоя работа.
Таким образом, вы можете решить, что и когда обновлять на странице.

В success() вам нужно получить ответ от flask и добавить/заменить HTML.

Но сначала: вам не обязательно отправлять всю страницу, а только часть - например <h1> и <img>.
И для этого вы можете использовать render_template_string().

def disp_image():

    # ... code ...

    return render_template_string('''       
<h1>Your generated image will appear here.</h1>
<img id = "picture" style = "height: 300px;" 
src = "{{url_for('static',filename='my-output.png')}}">
''')

А позже можно будет заменить только контент внутри <div id = "image-container">

$.ajax(

  // ... code ...

  success: function(response_data) {
    $('#image-container').html(response_data);
    alert('saved');
  }
)

Поскольку браузер может не перезагрузить изображение, если оно всегда будет иметь одно и то же имя, поскольку он не будет знать, что вы сохранили новое изображение с тем же именем, поэтому вы можете отправить изображение как base64 в src = "...".

def disp_image():

    # ... code ...

    img_data = encoded_img_data.decode('utf-8')

    return render_template_string('''       
<h1>Your generated image will appear here.</h1>
<img id = "picture" style = "height: 300px;" 
src = "data:image/png;base64, {{base64_image}}">
''', base64_image=img_data)

Кстати: после data:image/png;base64, есть один пробел.


Конечно можно отправлять только base64_image - т.е. как JSON — и JavaScript может получить его и заменить только src = "..." (если он уже существует на странице)

from flask import jsonify
                        
def disp_image():

    # ... code ...

    img_data = encoded_img_data.decode('utf-8')

    return jsonify({'base64_image': img_data})
success: function(response_data) {
    var json = $.parseJSON(response_data);
    var image = json.base64_image;
    $('#picture').attr('src', 'data:image/png;base64, ' + image);
    alert('saved');
}    

Полный рабочий код — с двумя версиями:

  • один отправляет HTML с h1 и img
  • другой отправляет JSON с помощью base64 и создает img в JavaScript

Оба используют PIL.Image для создания изображения с текстом.

import os
from flask import Flask, request, render_template_string
from PIL import Image, ImageDraw, ImageFont
import io
import base64

os.makedirs('static', exist_ok=True)

app = Flask(__name__)

@app.route('/')
def index():
    return render_template_string('''<!DOCTYPE html>
<html>
<head>
    <meta charset = "utf-8">
    <script src = "https://code.jquery.com/jquery-3.5.1.js" integrity = "sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc = "
            crossorigin = "anonymous"></script>    
</head>
<body>

<form target = "_blank" id = "text-form" action = "/my_prompt" method = "POST">
    <textarea id = "text-input" name = "text" rows = "5" placeholder = "e.g. A cat riding a bicycle on Mars"></textarea></br>
    <button type = "submit">Generate Image</button>
</form>

<form target = "_blank" id = "text-form-json" action = "/my_prompt_json" method = "POST">
    <textarea id = "text-input-json" name = "text" rows = "5" placeholder = "e.g. A cat riding a bicycle on Mars"></textarea></br>
    <button type = "submit">Generate Image</button>
</form>

<div id = "image-container">
<h1>No Image</h1>
</div>

<script type = "text/javascript">
$(document).on('submit', '#text-form', function (e) {
    e.preventDefault();
    console.info('button smashed');
    $.ajax({
        type: 'POST',
        url: '/my_prompt',
        data: {
            text: $("#text-input").val()
        },
        success: function(response_data) {
            $('#image-container').html(response_data);
        }
    })
});

$(document).on('submit', '#text-form-json', function (e) {
    e.preventDefault();
    console.info('button smashed JSON');
    $.ajax({
        type: 'POST',
        url: '/my_prompt_json',
        data: {
            text: $("#text-input-json").val()
        },
        success: function(response_data) {
            picture = $('#picture');
            if (picture.length === 0) {
                picture = $('<img id = "picture" style = "height: 300px;">');
            }
            picture.attr('src', 'data:image/png;base64, ' + response_data.base64_image);
            $('#image-container').html(picture);
        }
    })
});

</script>
</body>
</html>''')

def disp_image():  

    img = Image.open("static/my-output.png")
    data = io.BytesIO()
    img.save(data, 'PNG')
    encoded_img_data = base64.b64encode(data.getvalue())
    img_data=encoded_img_data.decode('utf-8')
    
    return render_template_string('''       
<h1>Your generated image will appear here.</h1>
<img id = "picture" style = "height: 300px;" 
src = "data:image/png;base64, {{base64_image}}">
''', base64_image=img_data)

from flask import jsonify
                        
def disp_image_json():

    img = Image.open("static/my-output.png")
    data = io.BytesIO()
    img.save(data, 'PNG')
    encoded_img_data = base64.b64encode(data.getvalue())
    img_data=encoded_img_data.decode('utf-8')

    return jsonify({'base64_image': img_data})

@app.route('/my_prompt', methods=['POST'])
def image():
    if request.method == "POST":
    
        text = request.form.get('text', '???')
        print('text:', text)
        
        img = Image.new('RGB', (600, 300))
        draw = ImageDraw.Draw(img)
        font = ImageFont.truetype("arial.ttf", size=40)
        draw.text((10, 10), text, font=font, fill=(255, 255, 255))
        img.save('static/my-output.png')
        
        return disp_image()

@app.route('/my_prompt_json', methods=['POST'])
def image_json():
    if request.method == "POST":
    
        text = request.form.get('text', '???')
        print('text:', text)
        
        img = Image.new('RGB', (600, 300))
        draw = ImageDraw.Draw(img)
        font = ImageFont.truetype("arial.ttf", size=40)
        draw.text((10, 10), text, font=font, fill=(255, 255, 255))
        img.save('static/my-output.png')
        
        return disp_image_json()

if __name__ == '__main__':
    app.debug = True 
    app.run()