“依赖下拉列表”不起作用[谷歌应用程序引擎上的Flask]

2024-09-27 18:00:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我是一个编码初学者。我想使用谷歌云文本到语音API制作一个简单的web应用程序

  1. 带有文本框的网站
  2. 在文本框中输入一句话,然后单击“提交”按钮
  3. 你可以下载一个由谷歌云文本制作的mp3文件到 语音接口

我是日本的一名英语教师,所以我希望我的学生能使用这个网站来提高他们的英语发音

首先,我想告诉你我的问题

我几乎完成了我的web应用程序。然而,发生了一个问题。从属下拉列表不起作用。 当用户使用该应用程序时,她选择国家/地区和voiceId

如果您选择我们-->;您可以从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,则会出现问题

Even if choose GB--> en-GB-Wavenet-B, you download a mp3 file which sounds voice of en-GB-Wavenet-A.

Also, even if choose GB--> en-GB-Wavenet-C, you download a mp3 file which sounds voice of en-GB-Wavenet-A.


其次,我想向您展示我的代码。 我在Google应用程序引擎标准环境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的问题,所以我搜索了互联网。 然而,我无法得到答案

你能给我一些信息或建议吗

先谢谢你

真的,卡祖


Tags: textnameimportappvaluevarselectmp3
1条回答
网友
1楼 · 发布于 2024-09-27 18:00:16

您的问题是有两个同名的select输入

当向服务器发送请求时,它只选择第一个,这可以是英国语音的默认值,也可以是美国语音的默认值(如果之前已选择)

为了使用具有相同名称的多个输入,您需要使用一对括号指定它们的名称,如下所示:

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

相关问题 更多 >

    热门问题