«зависимый выпадающий список» не работает [Flask в Google App Engine] - PullRequest
1 голос
/ 23 января 2020

Я новичок в кодировании. Я хотел бы создать простое веб-приложение, использующее Google Cloud Text to Speech API.

  1. веб-сайт с текстовым полем
  2. , введите предложение в текстовое поле и щелкните с помощью кнопки «отправить»
  3. вы можете загрузить mp3-файл, созданный Google Cloud Text, в Speech API

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

Во-первых, Я хотел бы рассказать вам о своей проблеме.

Я почти закончил мое веб-приложение. Однако возникла одна проблема. Зависимый раскрывающийся список не работает. Когда пользователь использует приложение, он выбирает страну и голосовой идентификатор.

Если вы выбираете США -> вы выбираете из en-US-Wav enet -A или en-US-Wav enet -B или en-US-Wav enet - C.

Если вы выбираете GB -> вы выбираете из en-GB-Wav enet -A или en-GB-Wav enet - B или en-GB-Wav enet - C.

Если вы выберете США, он отлично работает. Однако, если вы выбираете ГБ, возникает проблема.

Даже если вы выберете ГБ -> en-GB-Wav enet -B, вы скачиваете mp3-файл, который звучит как голос en-GB. -Wav enet -A.

Кроме того, даже если выбрать GB -> en-GB-Wav enet - C, вы скачиваете mp3-файл, который звучит как en-GB-Wav enet -A.


Во-вторых, Я бы хотел показать вам свой код. Я использую Flask в стандартной среде Google App Engine Python3 .7.

Это структура каталогов.

.
├── app.yaml
├── credentials.json
├── main.py
├── requirements.txt
└── templates
    └── index.html

Это main.py.

from flask import Flask
from flask import render_template
from flask import request
from flask import send_file
import os
from google.cloud import texttospeech

app = Flask(__name__)

@app.route("/", methods=['POST', 'GET'])
def index():
    if request.method == "POST":
        ssml = '<speak><prosody rate="slow">' + request.form['text'] + '</prosody></speak>'
        language = request.form['language']
        voiceid = request.form['voiceId']
        os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="credentials.json"

        client = texttospeech.TextToSpeechClient()
        input_text = texttospeech.types.SynthesisInput(ssml=ssml)
        voice = texttospeech.types.VoiceSelectionParams(
            language_code=language,
            name=voiceid)

        audio_config = texttospeech.types.AudioConfig(
            audio_encoding=texttospeech.enums.AudioEncoding.MP3)

        response = client.synthesize_speech(input_text, voice, audio_config)

        # The response's audio_content is binary.
        with open('/tmp/output.mp3', 'wb') as out:
            out.write(response.audio_content)

        return send_file("/tmp/output.mp3",as_attachment=True)
    else:
        return render_template("index.html")

if __name__ == "__main__":
    app.run()

Это индекс. html (некоторые объяснения написаны на японском языке, извините.).

<html>
<head>
    <style> 
         #text {width: 100%; height: 300px;}
    </style>
    <script type="text/javascript">
        // ▼HTMLの読み込み直後に実行:
        document.addEventListener('DOMContentLoaded', function() {

           // ▼2階層目の要素を全て非表示にする
           var allSubBoxes = document.getElementsByClassName("subbox");
           for( var i=0 ; i<allSubBoxes.length ; i++) {
              allSubBoxes[i].style.display = 'none';
           }

        });
    </script>
    <script type="text/javascript">
        // ▼HTMLの読み込み直後に実行:
        document.addEventListener('DOMContentLoaded', function() {

           // ▼全てのプルダウンメニューセットごとに処理
           var mainBoxes = document.getElementsByClassName('pulldownset');
           for( var i=0 ; i<mainBoxes.length ; i++) {

              var mainSelect = mainBoxes[i].getElementsByClassName("mainselect");   // 1階層目(メイン)のプルダウンメニュー(※後でvalue属性値を参照するので、select要素である必要があります。)
              mainSelect[0].onchange = function () {
                 // ▼同じ親要素に含まれているすべての2階層目(サブ)要素を消す
                 var subBox = this.parentNode.getElementsByClassName("subbox");   // 同じ親要素に含まれる.subbox(※select要素に限らず、どんな要素でも構いません。)
                 for( var j=0 ; j<subBox.length ; j++) {
                    subBox[j].style.display = 'none';
                 }

                 // ▼指定された2階層目(サブ)要素だけを表示する
                 if( this.value ) {
                    var targetSub = document.getElementById( this.value );   // 「1階層目のプルダウンメニューで選択されている項目のvalue属性値」と同じ文字列をid属性値に持つ要素を得る
                    targetSub.style.display = 'inline';
                 }
              }

           }

        });
    </script>
</head>

<body>
<form action="/" method="POST">

   <div class="pulldownset">

      <!-- ========================================== -->
      <select class="mainselect" name="language">
         <option value="">country</option>
         <option value="en-US">US</option>
         <option value="en-GB">GB</option>
      </select>

      <!-- ================================================================ -->
      <select id="en-US" class="subbox" name="voiceId">
         <option value="">voice</option>
         <option value="en-US-Wavenet-A">en-US-Wavenet-A</option>
         <option value="en-US-Wavenet-B">en-US-Wavenet-B</option>
         <option value="en-US-Wavenet-C">en-US-Wavenet-C</option>
      </select>

      <!-- ================================================================ -->
      <select id="en-GB" class="subbox" name="voiceId">
         <option value="">en-GB</option>
         <option value="en-GB-Wavenet-A">en-GB-Wavenet-A</option>
         <option value="en-GB-Wavenet-B">en-GB-Wavenet-B</option>
         <option value="en-GB-Wavenet-C">en-GB-Wavenet-C</option>
      </select>

   </div>

   <textarea id="text" name="text" placeholder="input text here"></textarea>
   <input type="submit" value="download">

</form>
</body>
</html>

Это файл require.txt.

Flask==1.1.1
future==0.18.2
google-cloud-texttospeech==0.5.0
grpcio==1.26.0
gunicorn

Это app.yaml .

runtime: python37
entrypoint: gunicorn -b :$PORT main:app

Я думал, что это проблема JavaScript, поэтому я искал Inte rnet. Однако я не смог получить ответ.

Не могли бы вы дать мне какую-либо информацию или предложение?

Заранее спасибо.

С уважением, Казу

1 Ответ

1 голос
/ 23 января 2020

Ваша проблема в том, что у вас есть 2 выбранных входа с одинаковым именем.

При отправке запроса на сервер он выбирает только первый, что может быть либо по умолчанию для голоса Briti sh. или американский голос, если он был выбран ранее.

Чтобы использовать несколько входов с одним и тем же именем, вам необходимо указать их имя с помощью пары скобок, например:

<select id="en-US" class="subbox" name="voiceId[]">

И

<select id="en-GB" class="subbox" name="voiceId[]">

И на стороне сервера вы можете найти первое вхождение идентификатора языка, чтобы определить, какой из элементов в списке должен быть назначен переменной.

Таким образом, вместо:

voiceid = request.form['voiceId']

У вас будет что-то вроде:

voiceid = next(voice for voice in request.form.getlist('voiceId[]') if language in voice)

РЕДАКТИРОВАТЬ:

Ниже приведена альтернатива без выражений генератора .

voices = []
for voice in request.form.getlist('voiceId[]'):
    if language in voice:
        voices.append(voice)

voiceid = next(iter(voices))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...