Lorsque vous avez un enregistrement où une ou plusieurs personnes parlent, il est utile d'avoir un moyen très précis et automatisé d'extraire les mots prononcés dans le texte. Une fois que vous avez le texte, vous pouvez l'utiliser pour une analyse plus approfondie ou comme fonctionnalité d'accessibilité.
Dans ce didacticiel, nous utiliserons une interface de programmation d'application Web de synthèse vocale de haute précision appelée AssemblyAI pour extraire le texte d'un enregistrement MP3 (de nombreux autres formats sont également pris en charge).
Avec le code de ce didacticiel, vous pourrez prendre un fichier audio contenant de la parole comme cet exemple que j'ai enregistré et produire une transcription de texte très précise comme celle-ci :
An object relational mapper is a code library that automates the transfer of data stored in relational, databases into objects that are more commonly used in application code or EMS are useful because they provide a high level abstraction upon a relational database that allows developers to write Python code instead of sequel to create read update and delete, data and schemas in their database. Developers can use the programming language. They are comfortable with to work with a database instead of writing SQL... (the text goes on from here but I abbreviated it at this point)
Exigences du didacticiel
Tout au long de ce didacticiel, nous allons utiliser les dépendances suivantes, que nous allons installer dans un instant. Assurez-vous également que Python 3, de préférence 3.6 ou une version plus récente, est installé dans votre environnement :
Nous utiliserons les dépendances suivantes pour terminer ce didacticiel :
- demande la version 2.24.0 pour envoyer des requêtes HTTP à l'API de synthèse vocale AssemblyAI
- Un compte AssemblyAI, auquel vous pouvez vous inscrire pour obtenir une clé d'accès API gratuite ici
Tout le code de cet article de blog est disponible en open source sous la licence MIT sur GitHub sous le répertoire transcribe-speech-text-script du référentiel blog-code-examples. Utilisez le code source comme vous le souhaitez pour vos propres projets.
Configuration de l'environnement de développement
Changez dans le répertoire où vous gardez vos environnements virtuels Python.Je garde le mien dans un sous-répertoire nommé venvs
dans le répertoire personnel de mon utilisateur. Créez un nouvel environnement virtuel pour ce projet à l'aide de la commande suivante.
python3 -m venv ~/venvs/pytranscribe
Activez le virtualenv avec le activate
script shell :
source ~/venvs/pytranscribe/bin/activate
Une fois la commande ci-dessus exécutée, l'invite de commande changera de sorte que le nom de virtualenv soit ajouté au format d'invite de commande d'origine, donc si votre invite est simplement $
, il ressemblera maintenant à ceci :
(pytranscribe) $
N'oubliez pas que vous devez activer votre environnement virtuel dans chaque nouvelle fenêtre de terminal où vous souhaitez utiliser des dépendances dans l'environnement virtuel.
Nous pouvons maintenant installer le requests
package dans le virtualenv activé mais autrement vide.
pip install requests==2.24.0
Recherchez une sortie similaire à la suivante pour confirmer que les packages appropriés ont été correctement installés à partir de PyPI.
(pytranscribe) $ pip install requests==2.24.0 Collecting requests==2.24.0 Using cached https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl Collecting certifi>=2017.4.17 (from requests==2.24.0) Using cached https://files.pythonhosted.org/packages/5e/c4/6c4fe722df5343c33226f0b4e0bb042e4dc13483228b4718baf286f86d87/certifi-2020.6.20-py2.py3-none-any.whl Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests==2.24.0) Using cached https://files.pythonhosted.org/packages/9f/f0/a391d1463ebb1b233795cabfc0ef38d3db4442339de68f847026199e69d7/urllib3-1.25.10-py2.py3-none-any.whl Collecting chardet<4,>=3.0.2 (from requests==2.24.0) Using cached https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl Collecting idna<3,>=2.5 (from requests==2.24.0) Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl Installing collected packages: certifi, urllib3, chardet, idna, requests Successfully installed certifi-2020.6.20 chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.10
Toutes nos dépendances requises sont installées afin que nous puissions commencer à coder l'application.
Mise en ligne, lancement et transcription audio
Nous avons tout ce dont nous avons besoin pour commencer à créer notre application qui transcrira l'audio en texte. Nous allons compiler cette application en trois fichiers :
- upload_audio_file.py :télécharge votre fichier audio dans un endroit sécurisé sur le service d'AssemblyAI afin qu'il puisse y accéder pour le traitement. Si votre fichier audio est déjà accessible avec une URL publique, vous n'avez pas besoin de faire cette étape, vous pouvez simplement suivre ce guide de démarrage rapide
- initiate_transcription.py :indique à l'API quel fichier transcrire et démarrer immédiatement
- get_transcription.py :imprime l'état de la transcription si elle est toujours en cours de traitement ou affiche les résultats de la transcription lorsque le processus est terminé
Créez un nouveau répertoire nommé pytranscribe
pour stocker ces fichiers au fur et à mesure que nous les écrivons. Passez ensuite au nouveau répertoire du projet.
mkdir pytranscribe cd pytranscribe
Nous devons également exporter notre clé API AssemblyAI en tant que variable d'environnement. Créez un compte AssemblyAI et connectez-vous au tableau de bord AssemblyAI, puis copiez "Votre jeton API" comme indiqué dans cette capture d'écran :
export ASSEMBLYAI_KEY=your-api-key-here
Notez que vous devez utiliser le export
commande dans chaque fenêtre de ligne de commande pour laquelle vous souhaitez que cette clé soit accessible. Les scripts que nous écrivons ne pourront pas accéder à l'API si vous n'avez pas le jeton exporté en tant que ASSEMBLYAI_KEY
dans l'environnement dans lequel vous exécutez le script.
Maintenant que notre répertoire de projet est créé et que la clé API est définie comme variable d'environnement, passons à l'écriture du code du premier fichier qui téléchargera les fichiers audio vers le service AssemblyAI.
Téléchargement du fichier audio pour la transcription
Créez un nouveau fichier nommé upload_audio_file.py
et placez-y le code suivant :
import argparse import os import requests API_URL = "https://api.assemblyai.com/v2/" def upload_file_to_api(filename): """Checks for a valid file and then uploads it to AssemblyAI so it can be saved to a secure URL that only that service can access. When the upload is complete we can then initiate the transcription API call. Returns the API JSON if successful, or None if file does not exist. """ if not os.path.exists(filename): return None def read_file(filename, chunk_size=5242880): with open(filename, 'rb') as _file: while True: data = _file.read(chunk_size) if not data: break yield data headers = {'authorization': os.getenv("ASSEMBLYAI_KEY")} response = requests.post("".join([API_URL, "upload"]), headers=headers, data=read_file(filename)) return response.json()
Le code ci-dessus importe le argparse
, os
et requests
packagesafin que nous puissions les utiliser dans ce script. Le API_URL
est une constante qui a l'URL de base du service AssemblyAI. Nous définissons leupload_file_to_api
fonction avec un seul argument, filename
qui devrait être une chaîne avec le chemin absolu vers un fichier et son nom de fichier.
Dans la fonction, nous vérifions que le fichier existe, puis utilisons l'encodage de transfert schunked de Request pour diffuser des fichiers volumineux vers l'API AssemblyAI.
Le os
getenv
du module la fonction lit l'API qui a été définie sur la ligne de commande en utilisant le export
commande avec le getenv
. Assurez-vous d'utiliser ce export
commande dans le terminal où vous exécutez ce script sinon que ASSEMBLYAI_KEY
la valeur sera vide. En cas de doute, utilisez echo $ASSEMBLY_AI
pour voir si la valeur correspond à votre clé API.
Pour utiliser le upload_file_to_api
fonction, ajoutez les lignes de code suivantes dans le upload_audio_file.py
fichier afin que nous puissions exécuter correctement ce code en tant que script appelé avec le python
commande :
if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("filename") args = parser.parse_args() upload_filename = args.filename response_json = upload_file_to_api(upload_filename) if not response_json: print("file does not exist") else: print("File uploaded to URL: {}".format(response_json['upload_url']))
Le code ci-dessus crée un ArgumentParser
objet qui permet à l'application d'obtenir un seul argument de la ligne de commande pour spécifier le fichier auquel nous voulons accéder, lire et télécharger sur le service AssmeblyAI.
Si le fichier n'existe pas, le script affichera un message indiquant que le fichier est introuvable. Dans le chemin heureux où nous trouvons le fichier correct à ce chemin, le fichier est téléchargé en utilisant le code dans upload_file_to_api
fonction.
Exécutez le upload_audio_file.py
terminé script en l'exécutant sur la ligne de commande avec le python
commande. Remplacer FULL_PATH_TO_FILE
avec un chemin absolu vers le fichier que vous souhaitez télécharger, tel que/Users/matt/devel/audio.mp3
.
python upload_audio_file.py FULL_PATH_TO_FILE
En supposant que le fichier se trouve à l'emplacement que vous avez spécifié, lorsque le script aura fini de télécharger le fichier, il imprimera un message comme celui-ci avec une URL unique :
File uploaded to URL: https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638
Cette URL n'est pas publique, elle ne peut être utilisée que par le service AssemblyAI, donc personne d'autre ne pourra accéder à votre fichier et à son contenu à part vous et leur API de transcription.
La partie qui est importante est la dernière section de l'URL, dans cet exemple c'est 463ce27f-0922-4ea9-9ce4-3353d84b5638
. Enregistrez cet identifiant unique car nous devons le transmettre au prochain script qui lance le service de transcription.
Lancer la transcription
Ensuite, nous allons écrire du code pour lancer la transcription. Créez un nouveau fichier nommé initiate_transcription.py
. Ajoutez le code suivant au nouveau fichier.
import argparse import os import requests API_URL = "https://api.assemblyai.com/v2/" CDN_URL = "https://cdn.assemblyai.com/" def initiate_transcription(file_id): """Sends a request to the API to transcribe a specific file that was previously uploaded to the API. This will not immediately return the transcription because it takes a moment for the service to analyze and perform the transcription, so there is a different function to retrieve the results. """ endpoint = "".join([API_URL, "transcript"]) json = {"audio_url": "".join([CDN_URL, "upload/{}".format(file_id)])} headers = { "authorization": os.getenv("ASSEMBLYAI_KEY"), "content-type": "application/json" } response = requests.post(endpoint, json=json, headers=headers) return response.json()
Nous avons les mêmes importations que le script précédent et nous avons ajouté une nouvelle constante, CDN_URL
qui correspond à l'URL distincte où AssemblyAIstocke les fichiers audio téléchargés.
Le initiate_transcription
La fonction configure essentiellement une seule requête HTTP à l'API AssemblyAI pour démarrer le processus de transcription sur le fichier audio à l'URL spécifique transmise. C'est pourquoi transmettre le file_id
est important :cela complète l'URL du fichier audio que nous demandons à AssemblyAI de récupérer.
Terminez le fichier en ajoutant ce code afin qu'il puisse être facilement invoqué à partir de la ligne de commande avec des arguments.
if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("file_id") args = parser.parse_args() file_id = args.file_id response_json = initiate_transcription(file_id) print(response_json)
Démarrez le script en exécutant le python
commande sur le initiate_transcription
fichier et transmettez l'identifiant de fichier unique que vous avez enregistré à l'étape précédente.
# the FILE_IDENTIFIER is returned in the previous step and will # look something like this: 463ce27f-0922-4ea9-9ce4-3353d84b5638 python initiate_transcription.py FILE_IDENTIFIER
L'API renverra une réponse JSON que ce script imprimera sur la ligne de commande.
{'audio_end_at': None, 'acoustic_model': 'assemblyai_default', 'text': None, 'audio_url': 'https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638', 'speed_boost': False, 'language_model': 'assemblyai_default', 'redact_pii': False, 'confidence': None, 'webhook_status_code': None, 'id': 'gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067', 'status': 'queued', 'boost_param': None, 'words': None, 'format_text': True, 'webhook_url': None, 'punctuate': True, 'utterances': None, 'audio_duration': None, 'auto_highlights': False, 'word_boost': [], 'dual_channel': None, 'audio_start_from': None}
Prenez note de la valeur du id
clé dans la réponse JSON. Il s'agit de l'identifiant de transcription que nous devons utiliser pour récupérer le résultat de la transcription. Dans cet exemple, il s'agit de gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067
. Copiez l'identifiant de transcription dans votre propre réponse, car nous en aurons besoin pour vérifier la fin du processus de transcription à l'étape suivante.
Récupérer le résultat de la transcription
Nous avons téléchargé et commencé le processus de transcription, alors obtenons le résultat dès qu'il est prêt.
Le temps nécessaire pour obtenir les résultats peut dépendre de la taille du fichier, donc ce prochain script enverra une requête HTTP à l'API et rendra compte de l'état de la transcription, ou imprimera la sortie si elle est terminée.
Créez un troisième fichier Python nommé get_transcription.py
et mettez-y le code suivant.
import argparse import os import requests API_URL = "https://api.assemblyai.com/v2/" def get_transcription(transcription_id): """Requests the transcription from the API and returns the JSON response.""" endpoint = "".join([API_URL, "transcript/{}".format(transcription_id)]) headers = {"authorization": os.getenv('ASSEMBLYAI_KEY')} response = requests.get(endpoint, headers=headers) return response.json() if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("transcription_id") args = parser.parse_args() transcription_id = args.transcription_id response_json = get_transcription(transcription_id) if response_json['status'] == "completed": for word in response_json['words']: print(word['text'], end=" ") else: print("current status of transcription request: {}".format( response_json['status']))
Le code ci-dessus a les mêmes importations que les autres scripts. Dans ce nouveau get_transcription
fonction, nous appelons simplement l'API AssemblyAI avec notre clé API et l'identifiant de transcription de l'étape précédente (pas l'identifiant du fichier). Nous récupérons la réponse JSON et la renvoyons.
Dans la fonction principale, nous traitons l'identifiant de transcription qui est transmis en tant qu'argument de ligne de commande et le transmettons au get_transcription
fonction. Si la réponse JSON du get_transcription
la fonction contient un completed
status puis nous imprimons les résultats de la transcription. Sinon, imprimez l'état actuel qui est soit queued
ou processing
avant c'est completed
.
Appelez le script à l'aide de la ligne de commande et de l'identifiant de transcription de la section précédente :
python get_transcription.py TRANSCRIPTION_ID
Si le service n'a pas encore commencé à travailler sur la transcription, il renverra queued
comme ceci :
current status of transcription request: queued
Lorsque le service travaille actuellement sur le fichier audio, il renverra processing
:
current status of transcription request: processing
Une fois le processus terminé, notre script renverra le texte de la transcription, comme vous le voyez ici :
An object relational mapper is a code library that automates the transfer of data stored in relational, databases into objects that are more commonly used in application code or EMS are useful because they provide a high level ...(output abbreviated)
Ça y est, nous avons notre transcription !
Vous vous demandez peut-être quoi faire si la précision n'est pas là où vous en avez besoin pour votre situation. C'est là qu'intervient l'amélioration de la précision des mots clés ou des expressions. Vous pouvez utiliser l'une ou l'autre de ces deux méthodes pour augmenter la précision de vos enregistrements à un niveau acceptable pour votre situation.
Quelle est la prochaine ?
Nous venons de finir d'écrire des scripts qui appellent l'API AssemblyAI pour transcrire des enregistrements avec parole en sortie texte.
Ensuite, jetez un œil à certaines de leurs documentations plus avancées qui vont au-delà des bases dans ce didacticiel :
- Formats de fichiers pris en charge
- Transcrire des enregistrements double canal/stéréo
- Obtenir des étiquettes de haut-parleur (diarisation du haut-parleur)
Des questions? Faites-le moi savoir via un ticket de problème sur le référentiel Full Stack Python, sur Twitter@fullstackpythonou @mattmakai.Vous voyez quelque chose qui ne va pas avec ce message ? La source de cette page sur GitHuband soumet une pull request.