Ревью функции преобразования текста в аудио

Основные риски — отсутствие валидации/timeout, утечка provider response в логи, блокирующая длинная цепочка и неверный MIME. Пустой text приводит к возврату None вместо HTTP-ответа.

Короткий ответ

Что ответить на собеседовании

Основные риски — отсутствие валидации/timeout, утечка provider response в логи, блокирующая длинная цепочка и неверный MIME. Пустой text приводит к возврату None вместо HTTP-ответа.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо выполнить код‑ревью функции text_to_voice, которая получает текст из тела запроса, отправляет его во внешнее API InferKit, затем с помощью Amazon Polly синтезирует речь, сохраняет полученный аудиофайл в S3 и возвращает предписанную ссылку на файл.

@swagger_auto_schema(method='post', request_body=RequestSerializer, responses={200: USER_RESPONSE, 400: BAD_RESPONSE})
@api_view(["POST"])
def text_to_voice(request):
    text = request.data.get("text")
    payload = {"length": 500}

    if text:
        payload["prompt"] = {"text": text}
        headers = {"Authorization": f"Bearer {settings.INFERKIT_API_KEY}"}
        response = requests.post(settings.INFERKIT_URL, headers=headers, json=payload)

        if response.status_code == 400 and "Out of generation credits" in response.text:
            return views.Response({"error_message": "Out of generation credits"}, status=400)

        if not response.ok:
            logger.error(f"Status code {response.status_code} from inferkit with {response.text}.")
            raise views.exceptions.ParseError("Text generation API failed. Please, try again.")

        response_text = response.json().get("data", {}).get("text") if response.ok else ""

        aws_kwargs = {
            "aws_access_key_id": settings.AWS_ACCESS_KEY_ID,
            "aws_secret_access_key": settings.AWS_SECRET_ACCESS_KEY
        }

        polly_client = boto3.Session(region_name=settings.AWS_REGION_NAME, **aws_kwargs).client("polly")
        generated_audio = polly_client.synthesize_speech(Text=response_text, OutputFormat=settings.AWS_FILE_TYPE, VoiceId="Joey", LanguageCode="en-US")

        s3_connection = boto3.resource("s3", **aws_kwargs)
        file_name = f"{datetime.now().isoformat()}.{settings.AWS_FILE_TYPE}"
        s3_connection.Bucket(settings.AWS_BUCKET_NAME).put_object(
            Key=file_name,
            Body=generated_audio.get("AudioStream").read(),
            ContentType=settings.AWS_FILE_TYPE
        )

        file_url = s3_connection.meta.client.generate_presigned_url(
            ClientMethod="get_object",
            Params={"Bucket": settings.AWS_BUCKET_NAME, "Key": file_name}
        )

        return views.Response({"message": response_text, "file_url": file_url})

Ответ

Основные риски — отсутствие валидации/timeout, утечка provider response в логи, блокирующая длинная цепочка и неверный MIME. Пустой text приводит к возврату None вместо HTTP-ответа.

Проверяйте RequestSerializer, длину и допустимость текста, структуру ответа API; swagger-декоратор сам этого не делает. Сетевые ошибки и сбои Polly/S3 обрабатывайте отдельно, не выдавая upstream-сбой как ошибку формата клиента. Не логируйте сырой ответ с текстом пользователя.

Используйте IAM-роли, уникальный ключ объекта и приватный bucket. Для MP3 нужен ContentType audio/mpeg, а не 'mp3'; AudioStream необходимо закрывать. Presigned URL имеет ограниченный срок жизни — задайте его явно. Голос и язык должны соответствовать тексту. Долгую генерацию лучше перенести в идемпотентную фоновую задачу с квотами и безопасным повтором.

Источник: docs.aws.amazon.com, docs.aws.amazon.com.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее