Как асинхронно генерировать аудиофайлы Google Text-To-Speech в представлении Django для использования на веб-странице? - PullRequest
0 голосов
/ 03 января 2019

Одна из моих веб-страниц занимает около 3 секунд для локальной загрузки и 15 секунд для загрузки в режиме реального времени на Heroku. Я считаю, что проблема заключается в том, сколько синхронных вызовов API Google TTS (Text-To-Speech) и синхронной базы данных / записей Amazon S3 я выполняю.

Я думаю, что асинхронное кодирование поможет, но я не совсем уверен, как его реализовать. Вот что происходит в представлении:

# views.py 

def convert_str_to_audio_info_if_necessary(audio_str):
    audio_info =  AudioInfo.objects.get_by_text(audio_str)
    if audio_info is None:
        audio_content = synthesize_text(audio_str) # returns audio file from Google
        # WAIT for the response to come back from Google's API
        new_audio = ContentFile(audio_content, 'audio.wav') # converts to file Python can read
        audio_info = AudioInfo.objects.create_problem_audio(text=audio_str, audio=new_audio, duration=get_audio_file_duration(new_audio))
        # WAIT for the audio file to be written to my S3 bucket
    return audio_info

def slow_loading_view(request):
    for i in range(100):
        audio_str = str(i)
        audio_info = convert_str_to_audio_info_if_necessary(audio_str)
        context[audio_str] = audio_info
    # Now I would like to pass this data in my context to use in the webpage
    return render(request, 'my_page.html', context)

И мой в моей модели:

# models.py

class AudioInfoManager(models.Manager):

    def get_by_text(self, text):
        qs = self.get_queryset().filter(text=text) 
        if len(qs) == 0:
            return None
        return qs[0]

    def create_problem_audio(self, text, audio, duration):
        already_created_entry = self.get_by_text(text)
        if already_created_entry != None:
            return already_created_entry
        problem_audio = self.create(text=text, audio=audio, duration=duration)
        return problem_audio


class AudioInfo(models.Model):
    text            = models.TextField(unique=True)
    audio           = models.FileField(upload_to=upload_audio_info_path)
    duration        = models.FloatField()

    objects         = AudioInfoManager()

Как вы можете видеть, в представлении происходит большое время ожидания (простоя), поэтому в идеале я бы смог 1) асинхронно отправлять все запросы API Google для создания аудиофайлов, а затем после того, как я вернуть все эти аудиофайлы 2) асинхронно записать эти аудиофайлы в базу данных и сегменты S3, а затем, как только они все будут записаны, 3) запросить в базе данных свои данные и передать данные в качестве контекста для отображения моей веб-страницы.

Кажется, что все асинхронные библиотеки в Django, такие как Celery и Redis Queue, помогают только в фоновых задачах (задачах, которые не требуется выполнять перед отображением веб-страницы представления, например, отправка электронных писем, запись данных в базу данных, которая не на веб-странице и т. д.). Возможно, каналы asyncio или Django - это решения? Django - это синхронный фреймворк, поэтому я не уверен, могу ли я обновлять базу данных асинхронно.

Есть предложения, что мне делать?

1 Ответ

0 голосов
/ 03 января 2019

Согласен, это не похоже на вариант использования для очереди задач с учетом текущей реализации.

Как вы упомянули, записи действительно занимают больше всего времени.

Есть несколько разных подходов, и они могут использоваться в комбинации:

  • кэш в памяти, чтобы избежать повторного вычисления (Redis, Memcached)
  • дескриптор пользовательского интерфейса (одно действие для преобразования в аудио, другое действие с полосой загрузки во время записи в БД)
  • асинхронная запись (собирать аудиофайлы для записи, отправки и передачи пользователю, который пишет в процессе); Я бы взял asyncio библиотеку , связанную с выпуском Python 3.7, если бы вы могли использовать более новые выпуски Django, которые поддерживают асинхронное .

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

...