簡體   English   中英

“依賴下拉列表”不起作用 [Google App Engine 上的 Flask]

[英]"dependent drop down list" does't work [Flask on Google App Engine]

我是編碼初學者。 我想使用 Google Cloud Text to Speech API 制作一個簡單的 Web 應用程序。

  1. 帶有文本框的網站
  2. 您在文本框中輸入一個句子,然后單擊“提交”按鈕
  3. 您可以下載由 Google Cloud Text to Speech API 制作的 mp3 文件

我是日本的英語老師,所以我希望我的學生使用這個網站來提高他們的英語發音。

首先,我想告訴你我的問題。

我幾乎完成了我的網絡應用程序。 然而,出現了一個問題。 相關下拉列表不起作用。 當用戶使用該應用程序時,她會選擇國家/地區和語音 ID。

如果您選擇 US--> 您可以選擇 en-US-Wavenet-A 或 en-US-Wavenet-B 或 en-US-Wavenet-C。

如果您選擇 GB--> 您可以選擇 en-GB-Wavenet-A 或 en-GB-Wavenet-B 或 en-GB-Wavenet-C。

如果您選擇美國,它可以完美運行。 但是,如果選擇GB,就會出現問題。

即使選擇GB--> en-GB-Wavenet-B,您下載的mp3文件聽起來像en-GB-Wavenet-A。

此外,即使選擇GB--> en-GB-Wavenet-C,您下載的mp3文件聽起來像en-GB-Wavenet-A。


其次,我想向您展示我的代碼。 我在 Google App Engine 標准環境 Python3.7 上使用 Flask。

這是目錄結構。

.
├── 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()

這是index.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>

這是requirements.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的問題,於是上網查了一下。 但是,我無法得到答案。

你能給我任何信息或建議嗎?

先感謝您。

真誠的,和

您的問題是您有 2 個同名的選擇輸入。

當向服務器發送請求時,它只選擇第一個,這可以是英國語音的默認值,也可以是美國語音(如果之前已選擇)。

為了使用具有相同名稱的多個輸入,您需要使用一對括號指定它們的名稱,如下所示:

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

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

在服務器端,您可以查找語言 ID 的第一次出現以確定列表中的哪些項目應分配給變量。

所以而不是:

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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM