Compare commits

..

27 Commits

Author SHA1 Message Date
89374d2418 up 2024-10-23 00:26:08 +02:00
f5d4a76db9 add patch from Damien.Allain 2023-03-07 11:45:43 +01:00
fe4129a4ee disable srt by default 2022-07-27 22:19:21 +02:00
27765e243d add doc for other models 2022-04-12 10:45:53 +02:00
4ce54d002c préciser le temps pris par la conversion en sous titre 2022-04-12 10:17:44 +02:00
0b79f0799d Merge branch 'master' of https://forge.chapril.org/tykayn/transcription 2022-04-12 09:25:54 +02:00
0160050928 ignore more folders 2022-04-12 09:25:20 +02:00
Kayn Ty
fd2c3bab33 check file exists 2021-08-18 16:26:49 +02:00
Kayn Ty
4ed0bcb786 up scripts 2021-03-27 14:38:39 +01:00
096400fbf2 hop 2021-03-27 10:30:38 +01:00
ccc48c09d7 ignore youtube-dl files in input folder 2021-03-27 10:10:56 +01:00
Kayn Ty
27b82d9d0d modify script ydl 2021-03-27 10:08:19 +01:00
Kayn Ty
b618dfe7c3 modify scripts to make it run on prod 2021-03-27 09:13:03 +01:00
tykayn
c0f2f4d225 youtube dl script ok to run directly, add en version for extract subtitles 2021-03-23 13:26:29 +01:00
ed4d03342d simple convert in en script 2021-03-23 12:54:53 +01:00
8d31bff32a advance on website script 2021-03-23 12:54:17 +01:00
590fcfd6ff add website style 2021-03-23 12:13:23 +01:00
tykayn
e784cec6ab update requirements 2021-03-23 12:06:27 +01:00
tykayn
9cbc47ea19 bouger modèle fr à l'installation 2021-03-23 11:20:50 +01:00
tykayn
32cb91f07d move website 2021-03-18 23:04:04 +01:00
tykayn
42fede81e5 add index webpage 2021-03-18 11:03:32 +01:00
29c19f6906 fix file name for outputs 2021-02-23 00:36:22 +01:00
2bc3b295b8 Merge branch 'master' of ssh://forge.chapril.org:222/tykayn/transcription 2021-02-21 11:39:52 +01:00
fa3b6bc744 fix count of lines in output, add name of original file to outputs 2021-02-21 11:35:48 +01:00
tykayn
6fd015290c verification de l'existence du modèle et du fichier demandé avant de lancer la transcription 2021-02-21 11:22:46 +01:00
tykayn
9f46ed3960 formats conversion files, a bash script for each. needs optimisation 2021-02-21 11:07:47 +01:00
db9f74b519 Merge pull request 'Mise à jour de README.md' (#2) from symeon/transcription:master into master
Reviewed-on: tykayn/transcription#2
2021-02-20 10:26:35 +01:00
44 changed files with 1337 additions and 130 deletions

11
.gitignore vendored Normal file → Executable file
View File

@ -1,7 +1,18 @@
/models/fr/*
/models/en/*
!/input/demo.wav
/input/*.ogg
/input/*.mp4
/input/*.mkv
/input/*.flac
/input/*.mp3
/input/converted_to_wav/*.wav
/input/already_converted/*
/output/**/*.txt
/output/**/*.csv
/output/**/*.json
/output/**/*.srt
.idea
input/ydl/*
input/fait/*
/vosk-model*

8
.idea/.gitignore vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/transcription-vosk.iml" filepath="$PROJECT_DIR$/.idea/transcription-vosk.iml" />
</modules>
</component>
</project>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/models" />
<excludeFolder url="file://$MODULE_DIR$/input/converted_to_wav" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

0
LICENSE.md Normal file → Executable file
View File

4
Makefile Normal file → Executable file
View File

@ -1,7 +1,11 @@
default: install
install:
bash install.sh
wav:
bash inputs_to_wav.sh
convert:
bash transcript.sh $(args)
convert_en:
bash english_transcript.sh $(args)
srt:
perl clean.sh $(args) > output/clean.srt

47
README.md Normal file → Executable file
View File

@ -2,33 +2,41 @@
configuration pour transcrire des fichiers audio wav avec Vosk
## mode d'emploi
## Mode d'emploi
### installation
#### Prérequis
* python3 (pour l'école serpentard)
* pip (gestionnaire de paquets python)
* pip3 version 19 (gestionnaire de paquets python)
* git (gestion de version)
* unzip (décompression de modèle)
* jq (pour le nettoyage de fichier json)
* ffmpeg (pour la conversion vers wav)
* youtube-dl si vous souhaitez utiliser le website
* 4Go de ram, 2Go serait trop juste pour utiliser le modèle fr par défaut.
* testé sur Ubuntu 20.04
pour les installer avec aptitude
```
sudo apt install jq python3-pip git ffmpeg
```
#### cloner ce dépot dans un dossier de travail
#### Cloner ce dépot dans un dossier de travail
```bash
git clone https://forge.chapril.org/tykayn/transcription.git && cd transcription
```
* installer vosk via le MakeFile, vérifiez les prérequis ci-dessus. une fois dans votre dossier de transcription fraîchement cloné, faites la commande:
```
```bash
make
```
* mettre un fichier audio dans le dossier "input"
* le convertir en wav mono (avec audacity par exemple)
* lancer la transcription du wav mono. Une démo est disponible, extraite de l'émission Libre à vous!
* le convertir en wav mono
```bash
make wav
```
* lancer la transcription du wav mono. Une démo est disponible, extraite de l'émission Libre à vous!
```bash
make convert file=input/demo.wav
```
n'oubliez pas l'argument `file=`
@ -43,10 +51,35 @@ Chaque fichier transcrit a un sous-dossier de son nom dans le dossier output. Ai
* si deux personnes parlent rapidement l'une après l'autre, vosk considèrera qu'il s'agit d'une seule phrase.
* les transcriptions peuvent être faites pour plusieurs langues, il faudra modifier le fichier "conversion_simple_fr.py" si on veut autre chose que du Français.
# évolutions possibles
# Évolutions possibles
- convertir un fichier mp3 vers WAV mono avec ffmpeg.
- nettoyer l'écho et normaliser le fichier audio.
- permettre le traitement en masse de plusieurs fichiers de podcast et leur donner un output nommé comme le fichier d'entrée afin de les distinguer.
# Modèles de voix
Common voice: 22Go
https://commonvoice.mozilla.org/fr/datasets
Other models
Other places where you can check for models which might be compatible:
https://kaldi-asr.org/models.html - variety of models from Kaldi - librispeech, aspire, chinese models
https://github.com/daanzu/kaldi-active-grammar/blob/master/docs/models.md - Big dictation models for English
https://github.com/uhh-lt/vosk-model-tuda-de - German models
https://github.com/german-asr/kaldi-german - Another German project
https://zamia-speech.org/asr/ - German and English model from Zamia
https://github.com/pguyot/zamia-speech/releases - French models for Zamia
https://github.com/opensource-spraakherkenning-nl/Kaldi_NL - Dutch model
https://montreal-forced-aligner.readthedocs.io/en/latest/pretrained_models.html (GMM models, not compatible but might be still useful)
https://github.com/goodatlas/zeroth - Korean Kaldi (just a recipe and data to train)
https://github.com/undertheseanlp/automatic_speech_recognition - Vietnamese Kaldi project
https://doc.linto.ai/#/services/linstt - LINTO project with French and English models
https://community.rhasspy.org/ - Rhasspy (some Kaldi models for Czech, probably even more)
https://github.com/feddybear/flipside_ph - Filipino model project by Federico Ang
https://github.com/alumae/kiirkirjutaja - Estonian Speech Recognition project with Vosk models
https://github.com/falabrasil/kaldi-br - Portuguese models from FalaBrasil project
https://github.com/egorsmkv/speech-recognition-uk - Ukrainian ASR project with Vosk models
https://github.com/Appen/UHV-OTS-Speech - repository from Appen for Scalable Data Annotation Pipeline for High-Quality Large Speech Datasets Development
https://github.com/vistec-AI/commonvoice-th - Thai models trained on CommonVoice
# liens
* [podcast libre à vous](https://cause-commune.fm/podcastfilter/libre-a-vous/)

74
base_transcript.sh Normal file
View File

@ -0,0 +1,74 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
file="input/already_converted/demo.wav"
echo "########### $(date) : conversion de fichier audio .WAV mono piste uniquement,
avec Vosk installé par pip3, et un modèle de textes en français."
echo " "
echo "########### $(date) : fichier : $file"
FOLDER_MODEL="fr"
# existence du modèle demandé
if [ -d "models/$FOLDER_MODEL" ]; then
echo "models/$FOLDER_MODEL le modèle est bien présent."
else
pwd
ls -l models
echo " "
echo "########### $(date) : [ERREUR] le modèle de données dans models/$FOLDER_MODEL n'existe pas, vérifiez son installation :C peut être avez vous oublié de faire une commande 'make'"
exit 1
fi
# existence du fichier demandé
if [ -f "$file" ]; then
echo "$file exists."
else
echo "########### $(date) : [ERREUR] voici les fichiers disponibles dans input/converted_to_wav: "
ls -l input/converted_to_wav
echo "########### $(date) : [ERREUR] le fichier $file n'existe PAS :C "
exit 1
fi
echo " "
FILE_NAME=$(basename $file .wav)
OUT_DIR=$( echo "output/$FILE_NAME")
mkdir output/$FILE_NAME
python3 ./extract_srt.py "$file" > $OUT_DIR/0_output.json
echo " "
echo "########### $(date) : nettoyer la sortie "
jq .text $OUT_DIR/0_output.json > $OUT_DIR/1_converted.txt
jq .text $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/1_converted_$FILE_NAME.txt
sed 's/null//g' $OUT_DIR/1_converted.txt > $OUT_DIR/2_without_nulls.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls.txt > $OUT_DIR/3_without_nulls.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls.txt > $OUT_DIR/4_phrases.txt
sed 's/null//g' $OUT_DIR/1_converted_$FILE_NAME.txt > $OUT_DIR/2_without_nulls_$FILE_NAME.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls_$FILE_NAME.txt > $OUT_DIR/3_without_nulls_$FILE_NAME.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls_$FILE_NAME.txt > $OUT_DIR/4_phrases_$FILE_NAME.txt
echo "########### $(date) : OK "
echo " "
COUNT_LINES=$(cat $OUT_DIR/phrases.txt |wc -l)
cat $OUT_DIR/4_phrases.txt
COUNT_LINES=$(cat $OUT_DIR/phrases_$FILE_NAME.txt |wc -l)
cat $OUT_DIR/4_phrases_$FILE_NAME.txt
echo " "
echo "########### $(date) : lignes transcriptes $COUNT_LINES "
echo "########### $(date) : conversion faite dans output/converted_out_without_nulls.txt"
echo "########### $(date) : conversion de la sortie en pseudo fichier de sous titres"
perl clean.sh $OUT_DIR/0_output.json > $OUT_DIR/5_phrases_min_sec.txt
perl clean.sh $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/5_phrases_min_sec_$FILE_NAME.txt
cat $OUT_DIR/5_phrases_min_sec.srt
echo "########### $(date) : conversion de la sortie en fichier de sous titres "
python3 ./extract_srt.py "$file" > $OUT_DIR/5_output.srt
python3 ./extract_srt.py "$file" > $OUT_DIR/5_output_$FILE_NAME.srt
ls -l $OUT_DIR
echo "########### $(date) : conversion faite "
exit 0

0
clean.sh Normal file → Executable file
View File

30
conversion_simple_en.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import wave
SetLogLevel(0)
if not os.path.exists("models/en"):
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'models' in the current folder.")
exit (1)
wf = wave.open(sys.argv[1], "rb")
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
print ("Audio file must be WAV format mono PCM.")
exit (1)
model = Model("models/en")
rec = KaldiRecognizer(model, wf.getframerate())
while True:
data = wf.readframes(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
print(rec.Result())
print(rec.FinalResult())

23
conversion_simple_fr.py Normal file → Executable file
View File

@ -1,22 +1,29 @@
#!/usr/bin/env python3
#!/usr/bin/python3
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import wave
SetLogLevel(0)
modelDir=os.path.dirname(sys.argv[0])+"/models/fr"
if not os.path.exists("model"):
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as 'model' in the current folder.")
SetLogLevel(0)
if not os.path.exists(modelDir):
print ("Please download the model from https://alphacephei.com/vosk/models and unpack as '{}'.".format(modelDir))
exit (1)
wf = wave.open(sys.argv[1], "rb")
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
print ("Audio file must be WAV format mono PCM.")
framerate=wf.getframerate()
nchannels=wf.getnchannels()
sampwidth=wf.getsampwidth()
comptype=wf.getcomptype()
if framerate < 16000 or nchannels != 1 or sampwidth != 2 or comptype != "NONE":
print ("Audio file has : {} Hz sample rate, {} channels, {} byte sample width and {} compression type".format(framerate, nchannels, sampwidth, comptype))
print ("when 16000 Hz sample rate, 1 channel, 2 byte sample width and NONE compression type are required")
exit (1)
model = Model("model")
model = Model(modelDir)
rec = KaldiRecognizer(model, wf.getframerate())
while True:
@ -25,7 +32,5 @@ while True:
break
if rec.AcceptWaveform(data):
print(rec.Result())
#else:
# print(rec.PartialResult())
print(rec.FinalResult())

View File

@ -0,0 +1,74 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
file="input/already_converted/audio_drive_thru.wav"
echo "########### $(date) : conversion de fichier audio .WAV mono piste uniquement,
avec Vosk installé par pip3, et un modèle de textes en français."
echo " "
echo "########### $(date) : fichier : $file"
FOLDER_MODEL="en"
# existence du modèle demandé
if [ -d "models/$FOLDER_MODEL" ]; then
echo "models/$FOLDER_MODEL le modèle est bien présent."
else
pwd
ls -l models
echo " "
echo "########### $(date) : [ERREUR] le modèle de données dans models/$FOLDER_MODEL n'existe pas, vérifiez son installation :C peut être avez vous oublié de faire une commande 'make'"
exit 1
fi
# existence du fichier demandé
if [ -f "$file" ]; then
echo "$file exists."
else
echo "########### $(date) : [ERREUR] voici les fichiers disponibles dans input/converted_to_wav: "
ls -l input/converted_to_wav
echo "########### $(date) : [ERREUR] le fichier $file n'existe PAS :C "
exit 1
fi
echo " "
FILE_NAME=$(basename $file .wav)
OUT_DIR=$( echo "output/$FILE_NAME")
mkdir -p output/$FILE_NAME
python3 ./extract_srt_en.py "$file" > $OUT_DIR/0_output.json
echo " "
echo "########### $(date) : nettoyer la sortie "
jq .text $OUT_DIR/0_output.json > $OUT_DIR/1_converted.txt
jq .text $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/1_converted_$FILE_NAME.txt
sed 's/null//g' $OUT_DIR/1_converted.txt > $OUT_DIR/2_without_nulls.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls.txt > $OUT_DIR/3_without_nulls.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls.txt > $OUT_DIR/4_phrases.txt
sed 's/null//g' $OUT_DIR/1_converted_$FILE_NAME.txt > $OUT_DIR/2_without_nulls_$FILE_NAME.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls_$FILE_NAME.txt > $OUT_DIR/3_without_nulls_$FILE_NAME.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls_$FILE_NAME.txt > $OUT_DIR/4_phrases_$FILE_NAME.txt
echo "########### $(date) : OK "
echo " "
COUNT_LINES=$(cat $OUT_DIR/phrases.txt |wc -l)
cat $OUT_DIR/4_phrases.txt
COUNT_LINES=$(cat $OUT_DIR/phrases_$FILE_NAME.txt |wc -l)
cat $OUT_DIR/4_phrases_$FILE_NAME.txt
echo " "
echo "########### $(date) : lignes transcriptes $COUNT_LINES "
echo "########### $(date) : conversion faite dans output/converted_out_without_nulls.txt"
echo "########### $(date) : conversion de la sortie en pseudo fichier de sous titres"
perl clean.sh $OUT_DIR/0_output.json > $OUT_DIR/5_phrases_min_sec.txt
perl clean.sh $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/5_phrases_min_sec_$FILE_NAME.txt
cat $OUT_DIR/5_phrases_min_sec.srt
echo "########### $(date) : conversion de la sortie en fichier de sous titres "
python3 ./extract_srt.py "$file" > $OUT_DIR/5_output.srt
python3 ./extract_srt.py "$file" > $OUT_DIR/5_output_$FILE_NAME.srt
ls -l $OUT_DIR
echo "########### $(date) : conversion faite "
exit 0

121
english_transcript.sh Executable file
View File

@ -0,0 +1,121 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
# ```bash
# bash transcript.sh myfile fr 1
# ```
echo " Transcript of a file - [file relative path \"input/aside/demo.wav\"] [lang en or fr] [enable srt conversion 1 or 0]"
# ----------------- Default parameters -----------------
#ENABLE_SRT=false
ENABLE_SRT=true
# disponibles: "fr" ou "en", trouvez d'autres modèles prédéfinis https://alphacephei.com/vosk/models
#FOLDER_MODEL="fr"
FOLDER_MODEL="en"
DEFAULT_FILE_TO_TRANSCRIPT="input/aside/demo.wav"
STARTTIME=$(date +%s)
# ----------------- prise en compte des arguments rentrés par l'utilisateur
echo "=====> langue: $FOLDER_MODEL"
echo "=====> fichier à convertir: $1"
if [ $1 ]; then
file=$1
else
echo "utilisation du fichier de démo"
file=$DEFAULT_FILE_TO_TRANSCRIPT
fi
if [ $2 ]; then
lang_to_search=$2
else
lang_to_search=$FOLDER_MODEL
fi
if [ $3 ]; then
ENABLE_SRT=$3
else
ENABLE_SRT=$ENABLE_SRT
fi
echo " [file name]: $file, [lang]: $lang_to_search, [enable srt conversion]: $ENABLE_SRT."
FILE_NAME=$(basename $file .wav)
output_dir="output"
if [ $2 ]; then
output_dir=$2
fi
OUT_DIR=$( echo "$output_dir/$FILE_NAME")
echo "########### $(date) : conversion de fichier audio .WAV mono piste uniquement,
avec Vosk installé par pip3, et un modèle de textes en Anglais."
echo " "
echo "########### $(date) : fichier : $file : $1"
# ----------------- recherche de l'existence du modèle de langue demandé -----------------
if [ -d "models/$lang_to_search" ]; then
echo "models/$lang_to_search le modèle est bien présent."
else
pwd
ls -l models
echo " "
echo "########### $(date) : [ERREUR] le modèle de données dans models/$lang_to_search n'existe pas, vérifiez son installation :C peut être avez vous oublié de faire une commande 'make'"
exit 1
fi
# ----------------- existence du fichier demandé -----------------
if [ -f "$file" ]; then
echo "$file exists."
else
echo "########### $(date) : [ERREUR] fichier introuvable: $file"
echo "########### $(date) : [ERREUR] voici les fichiers disponibles dans input/converted_to_wav: "
echo " "
ls -l input/converted_to_wav
echo " "
echo "########### $(date) : [ERREUR] le fichier $file n'existe PAS :C "
exit 1
fi
echo " "
mkdir output/$FILE_NAME -p
echo " convertir en sous titre ? $ENABLE_SRT"
if ($ENABLE_SRT) ; then
echo "########### $(date) : conversion de $file ,sortie en fichier de sous titres .srt"
echo ""
echo "## (cela prend plusieurs minutes généralement 1 / 10ème du temps du fichier audio)"
echo "..."
python3 ./extract_srt.py "$file" > $OUT_DIR/6_output_$FILE_NAME.srt
cat $OUT_DIR/6_output_$FILE_NAME.srt
COUNT_LINES=$(cat $OUT_DIR/6_output_$FILE_NAME.srt |wc -l)
echo " "
echo "-------------- DONE ------------"
echo " $COUNT_LINES lines in $OUT_DIR/6_phrases_min_sec.srt"
else
echo "########### $(date) : conversion de la sortie en divers fichiers marquant les temps et sans marquage"
python3 ./conversion_simple_en.py "$file" > $OUT_DIR/0_output_$FILE_NAME.json
echo " "
echo "########### $(date) : nettoyer la sortie "
jq .text $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/1_converted_$FILE_NAME.txt
sed 's/null//g' $OUT_DIR/1_converted_$FILE_NAME.txt > $OUT_DIR/2_without_nulls_$FILE_NAME.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls_$FILE_NAME.txt > $OUT_DIR/3_without_nulls_$FILE_NAME.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls_$FILE_NAME.txt > $OUT_DIR/4_phrases_$FILE_NAME.txt
echo "########### $(date) : OK "
echo " "
COUNT_LINES=$(cat $OUT_DIR/4_phrases_$FILE_NAME.txt |wc -l)
cat $OUT_DIR/4_phrases_$FILE_NAME.txt
echo " $COUNT_LINES lines in $OUT_DIR/4_phrases_$FILE_NAME.txt"
echo " "
echo "########### $(date) : lignes transcriptes $COUNT_LINES "
echo "########### $(date) : conversion faite dans output/converted_out_without_nulls.txt"
echo "########### $(date) : conversion de la sortie en pseudo fichier de sous titres"
perl clean.sh $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/5_phrases_min_sec_$FILE_NAME.txt
fi
echo "########### $(date) : conversion faite "
echo "########### en $SECONDS seconds"
exit 0

17
extract_srt.py Normal file → Executable file
View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3
# TODO tqdm
# prend un fichier audio et imprime des sous titres au format srt
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
@ -8,12 +9,16 @@ import json
import argparse
from collections import namedtuple
from pprint import pprint
import time
try:
from tqdm import tqdm
tqdm_installed = True
except:
tqdm_installed = False
start_time = time.time()
MODEL_LANG="fr"
class SubPart:
def __init__(self, start, end, text):
@ -37,7 +42,7 @@ class SubPart:
"""[1:-1]
def gen_subparts(input_file, model_dir, verbose=False, partlen=4, progress=False):
def gen_subparts(input_file, model_dir, verbose=False, partlen=4, progress=True):
SetLogLevel(0 if verbose else -1)
model = Model(model_dir)
@ -92,7 +97,7 @@ def gen_subparts(input_file, model_dir, verbose=False, partlen=4, progress=False
else:
pass
#print(rec.PartialResult())
#pprint(rec.PartialResult())
# pprint(rec.PartialResult())
if progress:
pbar.close()
r = json.loads(rec.PartialResult())
@ -115,16 +120,16 @@ def create_parser():
def main():
args = create_parser().parse_args()
if tqdm_installed:
it = enumerate(gen_subparts(args.input, "models/fr", args.verbose, args.interval, args.progress))
it = enumerate(gen_subparts(args.input, "models/"+MODEL_LANG, args.verbose, args.interval, args.progress))
else:
it = enumerate(gen_subparts(args.input, "models/fr", args.verbose, args.interval, False))
it = enumerate(gen_subparts(args.input, "models/"+MODEL_LANG, args.verbose, args.interval, False))
for i,subpart in it:
n = i+1
args.output.write(f"""{n}
{subpart}
"""
)
)

132
extract_srt_en.py Executable file
View File

@ -0,0 +1,132 @@
#!/usr/bin/env python3
# TODO tqdm
from vosk import Model, KaldiRecognizer, SetLogLevel
import sys
import os
import subprocess
import json
import argparse
from collections import namedtuple
from pprint import pprint
try:
from tqdm import tqdm
tqdm_installed = True
except:
tqdm_installed = False
class SubPart:
def __init__(self, start, end, text):
self.start = start
self.end = end
self.text = text
@staticmethod
def ftot(f):
h = int(f//3600)
m = int(f//60 % 60)
s = int(f//1 % 60)
ms = int((1000 * f) % 1000)
s = f"{h:02}:{m:02}:{s:02},{ms:03}"
return s
def __repr__(self):
return f"""
{self.ftot(self.start)} --> {self.ftot(self.end)}
{self.text}
"""[1:-1]
def gen_subparts(input_file, model_dir, verbose=False, partlen=4, progress=False):
SetLogLevel(0 if verbose else -1)
model = Model(model_dir)
rec = KaldiRecognizer(model, 16000)
process = subprocess.Popen(['ffmpeg', '-loglevel', 'quiet', '-i',
input_file,
'-ar', str(16000) , '-ac', '1', '-f', 's16le', '-'],
stdout=subprocess.PIPE)
r = subprocess.run("ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1".split() + [input_file], stdout=subprocess.PIPE)
duration = float(r.stdout.decode('utf-8').strip())
if progress:
pbar = tqdm(total=duration, unit="s")
prev_end = 0
while True:
data = process.stdout.read(4000)
if len(data) == 0:
break
if rec.AcceptWaveform(data):
r = json.loads(rec.Result())
if 'result' in r:
resultpart = [] # TODO: use this across AccesptForm
for result in r['result']:
if len(resultpart) > 0 and float(result['end']) - float(resultpart[0]['start']) >= partlen:
yield SubPart(start=resultpart[0]['start'],
end=float(resultpart[-1]['end']),
text=" ".join(r['word'] for r in resultpart))
prev_end = float(resultpart[-1]['end'])
resultpart = []
if float(result['end'] - result['start']) >= partlen:
yield SubPart(start=float(result['start']),
end=float(result['end']),
text=result['word'])
prev_end = float(result['end'])
resultpart = []
else:
resultpart.append(result)
if progress:
pbar.update(float(result['end'] - pbar.n))
if len(resultpart) > 0:
yield SubPart(start=float(resultpart[0]['start']),
end=float(resultpart[-1]['end']),
text=" ".join(r['word'] for r in resultpart))
prev_end = float(resultpart[-1]['end'])
resultpart = []
else:
pass
#print(rec.PartialResult())
#pprint(rec.PartialResult())
if progress:
pbar.close()
r = json.loads(rec.PartialResult())
text = r['partial']
yield SubPart(start=prev_end, end=duration, text=text)
def create_parser():
parser = argparse.ArgumentParser(prog="SRT file extractor using Speech-To-Text")
parser.add_argument("-v", "--verbose", action="store_true")
parser.add_argument("-o", "--output", type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument("-m", "--model", required=False)
parser.add_argument("-i", "--interval", default=4)
if tqdm_installed:
parser.add_argument("-p", "--progress", action="store_true")
parser.add_argument("input")
return parser
def main():
args = create_parser().parse_args()
if tqdm_installed:
it = enumerate(gen_subparts(args.input, "models/en", args.verbose, args.interval, args.progress))
else:
it = enumerate(gen_subparts(args.input, "models/en", args.verbose, args.interval, False))
for i,subpart in it:
n = i+1
args.output.write(f"""{n}
{subpart}
"""
)
if __name__ == "__main__":
main()

0
input/.gitkeep Normal file → Executable file
View File

0
input/demo.wav → input/aside/demo.wav Normal file → Executable file
View File

0
input/converted_to_wav/.gitkeep Normal file → Executable file
View File

89
inputs_to_wav.sh Executable file
View File

@ -0,0 +1,89 @@
#!/bin/bash
# utilisation: bash inputs_to_wav.sh
# auteur du script: tykayn contact@cipherbliss.com
echo "########### conversion des fichiers audio (mkv, mp3, mp4, ogg, webm, wav, avi) placés dans le dossier input, vers du wav mono-piste uniquement dans le dossier input/converted_to_wav"
echo " "
cd input
if -f already_converted; then
mkdir already_converted
fi
for i in *.avi; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%avi}wav"
echo " converti en WAV, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.flac; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%flac}wav"
echo " converti en WAV, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.mkv; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%mkv}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.mp3; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%mp3}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.mp4; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%mp4}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.ogg; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%ogg}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.webm; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%webm}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
for i in *.wav; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%wav}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
COUNT_LINES=$(ls -l input/converted_to_wav | wc -l)
echo "########### fichiers wav dans le dossier input/converted_to_wav: $COUNT_LINES "
echo "########### conversion faite dans output/converted_out_without_nulls.txt"
exit 0

32
install.sh Normal file → Executable file
View File

@ -25,15 +25,36 @@ pip3 --version
echo -e " ${reset}"
pip3 -v install vosk
echo "${green}########### récupération du modèle de reconnaissance en Français sous licence aGPL, taille: 1.6Go. Choix des modèles disponibles: https://alphacephei.com/vosk/models ${reset}"
echo " "
mkdir -p models/fr
echo -e "${green}########### Procéder au téléchargement du modèle Français (1.6go) pour transcrire les textes ?${reset} (écrivez o pour oui et faites entrée pour valider) ${reset}"
read proceed
# les autres modèles sont ici https://alphacephei.com/vosk/models
if [[ $proceed == o* ]]; then
echo "C'est parti."
wget https://alphacephei.com/vosk/models/vosk-model-fr-0.6-linto-2.2.0.zip
echo -e "${green}########### téléchargement du modèle OK ${reset}"
unzip vosk-model-fr-0.6-linto-2.2.0.zip
ln -s vosk-model-fr-0.6-linto-2.2.0 model
echo -e "${green}########### décompression du modèle OK ${reset}"
if [ ! -f "vosk-model-fr-0.6-linto-2.2.0.zip" ]; then
echo "Récupération du modèle en Français vosk-model-fr-0.6-linto-2.2.0.zip"
wget https://alphacephei.com/vosk/models/vosk-model-fr-0.6-linto-2.2.0.zip
echo -e "${green}########### téléchargement du modèle OK ${reset}"
unzip vosk-model-fr-0.6-linto-2.2.0.zip
mv vosk-model-fr-0.6-linto-2.2.0 models/fr
echo -e "${green}########### décompression du modèle en Français OK ${reset}"
ls -l models/fr
else
echo "fichier zip vosk-model-fr-0.6-linto-2.2.0.zip déjà présent"
fi
if [ ! -f "vosk-model-en-us-0.42-gigaspeech.zip" ]; then
echo "Récupération du modèle en Anglais vosk-model-fr-0.6-linto-2.2.0.zip"
wget https://alphacephei.com/vosk/models/vosk-model-en-us-0.42-gigaspeech.zip
echo -e "${green}########### téléchargement du modèle OK ${reset}"
unzip vosk-model-en-us-0.42-gigaspeech.zip
mv vosk-model-en-us-0.42-gigaspeech.zip models/en
echo -e "${green}########### décompression du modèle en Français OK ${reset}"
ls -l models/en
else
echo "fichier zip vosk-model-fr-0.6-linto-2.2.0.zip déjà présent"
fi
else
echo -e "${green}########### vous n'avez pas souhaité télécharger le modèle ${reset}"
echo -e "${green}########### fin de l'installation sans télécharger de modèle de langue ${reset}"
@ -43,3 +64,4 @@ fi
echo -e "${green}########### installation ok ${reset}"
exit 0

44
log_ydl.txt Executable file
View File

@ -0,0 +1,44 @@
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Mar 27 14:43 mono_canal.wav
Sat Mar 27 14:43:32 CET 2021 ###### end conversion __ 2021-Mar-27_1616852609 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Mar 27 21:48 mono_canal.wav
Sat Mar 27 21:48:48 CET 2021 ###### end conversion __ 2021-Mar-27_1616878123 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Apr 20 17:19 mono_canal.wav
Tue Apr 20 17:19:20 CEST 2021 ###### end conversion __ 2021-Apr-20_1618931951 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Apr 20 17:37 mono_canal.wav
Tue Apr 20 17:37:31 CEST 2021 ###### end conversion __ 2021-Apr-20_1618933048 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:09 mono_canal.wav
Wed Aug 18 16:09:53 CEST 2021 ###### end conversion __ 2021-Aug-18_1629295789 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:10 mono_canal.wav
Wed Aug 18 16:10:50 CEST 2021 ###### end conversion __ 2021-Aug-18_1629295848 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:12 mono_canal.wav
Wed Aug 18 16:12:13 CEST 2021 ###### end conversion __ 2021-Aug-18_1629295930 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:14 mono_canal.wav
Wed Aug 18 16:14:15 CEST 2021 ###### end conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:14 mono_canal.wav
Wed Aug 18 16:15:56 CEST 2021 ###### end conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:14 mono_canal.wav
Wed Aug 18 16:16:17 CEST 2021 ###### end conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
total 1708
-rw-r--r-- 1 www-data www-data 271266 Mar 23 09:48 base.mp3
-rw-r--r-- 1 www-data www-data 1470542 Aug 18 16:14 mono_canal.wav
Wed Aug 18 16:17:22 CEST 2021 ###### end conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d

80
microphone.py Normal file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env python3
import argparse
import queue
import sys
import sounddevice as sd
from vosk import Model, KaldiRecognizer
q = queue.Queue()
def int_or_str(text):
"""Helper function for argument parsing."""
try:
return int(text)
except ValueError:
return text
def callback(indata, frames, time, status):
"""This is called (from a separate thread) for each audio block."""
if status:
print(status, file=sys.stderr)
q.put(bytes(indata))
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
"-l", "--list-devices", action="store_true",
help="show list of audio devices and exit")
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
"-f", "--filename", type=str, metavar="FILENAME",
help="audio file to store recording to")
parser.add_argument(
"-d", "--device", type=int_or_str,
help="input device (numeric ID or substring)")
parser.add_argument(
"-r", "--samplerate", type=int, help="sampling rate")
args = parser.parse_args(remaining)
try:
if args.samplerate is None:
device_info = sd.query_devices(args.device, "input")
# soundfile expects an int, sounddevice provides a float:
args.samplerate = int(device_info["default_samplerate"])
model = Model("models/fr")
if args.filename:
dump_fn = open(args.filename, "wb")
else:
dump_fn = None
with sd.RawInputStream(samplerate=args.samplerate, blocksize = 8000, device=args.device,
dtype="int16", channels=1, callback=callback):
print("#" * 80)
print("Press Ctrl+C to stop the recording")
print("#" * 80)
rec = KaldiRecognizer(model, args.samplerate)
while True:
data = q.get()
if rec.AcceptWaveform(data):
print(rec.Result())
# else:
# print(rec.PartialResult())
if dump_fn is not None:
dump_fn.write(data)
except KeyboardInterrupt:
print("\nDone")
parser.exit(0)
except Exception as e:
parser.exit(type(e).__name__ + ": " + str(e))

0
models/.gitkeep Normal file → Executable file
View File

View File

@ -1,20 +0,0 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
echo "########### conversion des fichiers audio .ogg placés dans le dossier input, vers du wav mono-piste uniquement"
echo " "
for i in input/*.mp3; do
ffmpeg -acodec libvorbis -i "$i" -acodec pcm_s16le "input/converted_to_wav/${i%mp3}wav"
done
echo " "
echo "########### OK "
echo " "
COUNT_LINES_OGG=$(ll input/*.ogg |wc -l)
COUNT_LINES=$(ll input/converted_to_wav |wc -l)
echo "########### fichiers ogg dans le dossier input: $COUNT_LINES_OGG "
echo "########### fichiers wav dans le dossier input: $COUNT_LINES "
echo "########### conversion faite dans output/converted_out_without_nulls.txt"
exit 0

View File

@ -1,21 +0,0 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
echo "########### conversion des fichiers audio .ogg dans le dossier input, vers du wav mono-piste uniquement,
avec Vosk installé par pip3, et un modèle de textes en français."
echo " "
for i in input/*.ogg; do
ffmpeg -acodec libvorbis -i "$i" -acodec pcm_s16le "input/converted_to_wav/${i%ogg}wav"
done
echo " "
echo "########### OK "
echo " "
COUNT_LINES_OGG=$(ll input/*.ogg |wc -l)
COUNT_LINES=$(ll input/converted_to_wav |wc -l)
echo "########### fichiers ogg dans le dossier input: $COUNT_LINES_OGG "
echo "########### fichiers wav dans le dossier input: $COUNT_LINES "
echo "########### conversion faite dans output/converted_out_without_nulls.txt"
exit 0

0
output/.gitkeep Normal file → Executable file
View File

76
setup.py Normal file
View File

@ -0,0 +1,76 @@
import os
import setuptools
import shutil
import glob
import platform
# Figure out environment for cross-compile
vosk_source = os.getenv("VOSK_SOURCE", os.path.abspath(os.path.join(os.path.dirname(__file__),
"..")))
system = os.environ.get('VOSK_PLATFORM', platform.system())
architecture = os.environ.get('VOSK_ARCHITECTURE', platform.architecture()[0])
# Copy precompmilled libraries
for lib in glob.glob(os.path.join(vosk_source, "src/lib*.*")):
print ("Adding library", lib)
shutil.copy(lib, "vosk")
# Create OS-dependent, but Python-independent wheels.
try:
from wheel.bdist_wheel import bdist_wheel
except ImportError:
cmdclass = {}
else:
class bdist_wheel_tag_name(bdist_wheel):
def get_tag(self):
abi = 'none'
if system == 'Darwin':
oses = 'macosx_10_6_universal2'
elif system == 'Windows' and architecture == '32bit':
oses = 'win32'
elif system == 'Windows' and architecture == '64bit':
oses = 'win_amd64'
elif system == 'Linux' and architecture == '64bit':
oses = 'linux_x86_64'
elif system == 'Linux' and architecture == 'aarch64':
oses = 'manylinux2014_aarch64'
elif system == 'Linux':
oses = 'linux_' + architecture
else:
raise TypeError("Unknown build environment")
return 'py3', abi, oses
cmdclass = {'bdist_wheel': bdist_wheel_tag_name}
with open("README.md", "rb") as fh:
long_description = fh.read().decode("utf-8")
setuptools.setup(
name="vosk",
version="0.3.43",
author="Alpha Cephei Inc",
author_email="contact@alphacephei.com",
description="Offline open source speech recognition API based on Kaldi and Vosk",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/alphacep/vosk-api",
packages=setuptools.find_packages(),
package_data = {'vosk': ['*.so', '*.dll', '*.dyld']},
entry_points = {
'console_scripts': ['vosk-transcriber=vosk.transcriber.cli:main'],
},
include_package_data=True,
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: Apache Software License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS :: MacOS X',
'Topic :: Software Development :: Libraries :: Python Modules'
],
cmdclass=cmdclass,
python_requires='>=3',
zip_safe=False, # Since we load so file from the filesystem, we can not run from zip file
setup_requires=['cffi>=1.0', 'requests', 'tqdm', 'srt', 'websockets'],
install_requires=['cffi>=1.0', 'requests', 'tqdm', 'srt', 'websockets'],
cffi_modules=['vosk_builder.py:ffibuilder'],
)

58
transcribe_2.py Normal file
View File

@ -0,0 +1,58 @@
from vosk import Model, KaldiRecognizer, SetLogLevel
from tqdm.notebook import tqdm
import wave
import os
import json
def transcript_file(input_file, model_path):
# Check if file exists
if not os.path.isfile(input_file):
raise FileNotFoundError(os.path.basename(input_file) + " not found")
# Check if model path exists
if not os.path.exists(model_path):
raise FileNotFoundError(os.path.basename(model_path) + " not found")
# open audio file
wf = wave.open(input_file, "rb")
# check if wave file has the right properties
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
raise TypeError("Audio file must be WAV format mono PCM.")
# Initialize model
model = Model(model_path)
rec = KaldiRecognizer(model, wf.getframerate())
# Get file size (to calculate progress bar)
file_size = os.path.getsize(input_file)
# Run transcription
pbar = tqdm(total=file_size)
# To store our results
transcription = []
while True:
data = wf.readframes(4000) # use buffer of 4000
pbar.update(len(data))
if len(data) == 0:
pbar.set_description("Transcription finished")
break
if rec.AcceptWaveform(data):
# Convert json output to dict
result_dict = json.loads(rec.Result())
# Extract text values and append them to transcription list
transcription.append(result_dict.get("text", ""))
# Get final bits of audio and flush the pipeline
final_result = json.loads(rec.FinalResult())
transcription.append(final_result.get("text", ""))
transcription_text = ' '.join(transcription)
return transcription_text
wave_file = '/input/already_converted/drive_thu.wav'
transcription = transcript_file(wave_file, 'models/en')

136
transcript.sh Normal file → Executable file
View File

@ -1,42 +1,120 @@
#!/bin/bash
# utilisation: bash transcript.sh MONFICHIER.wav
# auteur du script: tykayn contact@cipherbliss.com
# ```bash
# bash transcript.sh myfile fr 1
# ```
echo " Transcript of a file - [file relative path \"input/aside/demo.wav\"] [lang en or fr] [enable srt conversion 1 or 0]"
# ----------------- Default parameters -----------------
#ENABLE_SRT=false
ENABLE_SRT=true
# disponibles: "fr" ou "en", trouvez d'autres modèles prédéfinis https://alphacephei.com/vosk/models
FOLDER_MODEL="fr"
#FOLDER_MODEL="en"
DEFAULT_FILE_TO_TRANSCRIPT="input/aside/demo.wav"
STARTTIME=$(date +%s)
# ----------------- prise en compte des arguments rentrés par l'utilisateur
echo "=====> langue: $FOLDER_MODEL"
echo "=====> fichier à convertir: $1"
if [ $1 ]; then
file=$1
else
echo "utilisation du fichier de démo"
file=$DEFAULT_FILE_TO_TRANSCRIPT
fi
if [ $2 ]; then
lang_to_search=$2
else
lang_to_search=$FOLDER_MODEL
fi
if [ $3 ]; then
ENABLE_SRT=$3
else
ENABLE_SRT=$ENABLE_SRT
fi
echo " [file name]: $file, [lang]: $lang_to_search, [enable srt conversion]: $ENABLE_SRT."
FILE_NAME=$(basename $file .wav)
output_dir="output"
if [ $2 ]; then
output_dir=$2
fi
OUT_DIR=$( echo "$output_dir/$FILE_NAME")
echo "########### $(date) : conversion de fichier audio .WAV mono piste uniquement,
avec Vosk installé par pip3, et un modèle de textes en français."
echo " "
echo "########### $(date) : fichier : $file"
echo "########### $(date) : fichier : $file : $1"
# ----------------- recherche de l'existence du modèle de langue demandé -----------------
if [ -d "models/$lang_to_search" ]; then
echo "models/$lang_to_search le modèle est bien présent."
else
pwd
ls -l models
echo " "
echo "########### $(date) : [ERREUR] le modèle de données dans models/$lang_to_search n'existe pas, vérifiez son installation :C peut être avez vous oublié de faire une commande 'make'"
exit 1
fi
# ----------------- existence du fichier demandé -----------------
if [ -f "$file" ]; then
echo "$file exists."
else
echo "########### $(date) : [ERREUR] fichier introuvable: $file"
echo "########### $(date) : [ERREUR] voici les fichiers disponibles dans input/converted_to_wav: "
echo " "
ls -l input/converted_to_wav
echo " "
echo "########### $(date) : [ERREUR] le fichier $file n'existe PAS :C "
exit 1
fi
echo " "
FILE_NAME=$(basename $file .wav)
OUT_DIR=$( echo "output/$FILE_NAME")
mkdir output/$FILE_NAME
python3 ./conversion_simple_fr.py "$file" > $OUT_DIR/0_output.json
mkdir -p "$OUT_DIR"
echo " convertir en sous titre ? $ENABLE_SRT"
if ($ENABLE_SRT) ; then
echo "########### $(date) : conversion de $file ,sortie en fichier de sous titres .srt"
echo ""
echo "## (cela prend plusieurs minutes généralement 1 / 10ème du temps du fichier audio)"
echo "..."
python3 ./extract_srt.py "$file" > $OUT_DIR/6_output_$FILE_NAME.srt
cat $OUT_DIR/6_output_$FILE_NAME.srt
COUNT_LINES=$(cat $OUT_DIR/6_output_$FILE_NAME.srt |wc -l)
echo " "
echo "-------------- DONE ------------"
echo " $COUNT_LINES lines in $OUT_DIR/6_phrases_min_sec.srt"
else
echo "########### $(date) : conversion de la sortie en divers fichiers marquant les temps et sans marquage"
python3 ./conversion_simple_fr.py "$file" > $OUT_DIR/0_output_$FILE_NAME.json
echo " "
echo "########### $(date) : nettoyer la sortie "
jq .text $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/1_converted_$FILE_NAME.txt
sed 's/null//g' $OUT_DIR/1_converted_$FILE_NAME.txt > $OUT_DIR/2_without_nulls_$FILE_NAME.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls_$FILE_NAME.txt > $OUT_DIR/3_without_nulls_$FILE_NAME.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls_$FILE_NAME.txt > $OUT_DIR/4_phrases_$FILE_NAME.txt
echo "########### $(date) : OK "
echo " "
COUNT_LINES=$(cat $OUT_DIR/4_phrases_$FILE_NAME.txt |wc -l)
cat $OUT_DIR/4_phrases_$FILE_NAME.txt
echo " $COUNT_LINES lines in $OUT_DIR/4_phrases_$FILE_NAME.txt"
echo " "
echo "########### $(date) : lignes transcriptes $COUNT_LINES "
echo "########### $(date) : conversion faite dans output/converted_out_without_nulls.txt"
echo "########### $(date) : conversion de la sortie en pseudo fichier de sous titres"
perl clean.sh $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/5_phrases_min_sec_$FILE_NAME.txt
fi
#ls -l $OUT_DIR
echo " "
echo "########### $(date) : nettoyer la sortie "
jq .text $OUT_DIR/0_output.json > $OUT_DIR/1_converted.txt
sed 's/null//g' $OUT_DIR/1_converted.txt > $OUT_DIR/2_without_nulls.txt
sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls.txt > $OUT_DIR/3_without_nulls.txt
sed 's/\"//g' $OUT_DIR/3_without_nulls.txt > $OUT_DIR/4_phrases.txt
echo "########### $(date) : OK "
echo " "
COUNT_LINES=$(cat $OUT_DIR/phrases.txt |wc -l)
cat $OUT_DIR/4_phrases.txt
echo " "
echo "########### $(date) : lignes transcriptes $COUNT_LINES "
echo "########### $(date) : conversion faite dans output/converted_out_without_nulls.txt"
echo "########### $(date) : conversion de la sortie en pseudo fichier de sous titres"
perl clean.sh $OUT_DIR/0_output.json > $OUT_DIR/5_phrases_min_sec.txt
cat $OUT_DIR/5_phrases_min_sec.srt
echo "########### $(date) : conversion de la sortie en fichier de sous titres "
python3 ./extract_srt.py "$file" > $OUT_DIR/5_output.srt
ls -l $OUT_DIR
echo "########### $(date) : conversion faite "
echo "########### $($STARTTIME) -- $(date) : conversion faite "
echo "########### en $SECONDS seconds"
exit 0

14
vosk_builder.py Normal file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env python3
import os
from cffi import FFI
vosk_root=os.environ.get("VOSK_SOURCE", "..")
cpp_command = "cpp " + vosk_root + "/src/vosk_api.h"
ffibuilder = FFI()
ffibuilder.set_source("vosk.vosk_cffi", None)
ffibuilder.cdef(os.popen(cpp_command).read())
if __name__ == '__main__':
ffibuilder.compile(verbose=True)

32
wav_to_wav_mono.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
# utilisation: bash wav_to_wav.sh
# auteur du script: tykayn contact@cipherbliss.com
echo "########### conversion des fichiers audio .wav placés dans le dossier input, vers du wav mono-piste uniquement dans le dossier input/converted_to_wav"
echo " "
cd input
mkdir already_converted
for i in *.wav; do
echo "fichier à traiter: $i"
ffmpeg -i "$i" -ac 1 "converted_to_wav/${i%wav}wav"
echo " converti en WAv, déplacement dans le dossier input/already_converted"
mv "$i" already_converted/
done
echo " "
echo "########### OK "
echo "########### fichiers wav restant dans le dossier input "
ls -l *.wav
cd ..
echo " "
COUNT_LINES_ORIGIN=$(ls -l input/*.wav |wc -l)
COUNT_LINES=$(ls -l input/converted_to_wav |wc -l)
echo "########### fichiers wav dans le dossier input: $COUNT_LINES_ORIGIN "
echo "########### fichiers wav dans le dossier input/converted_to_wav: $COUNT_LINES "
echo "########### conversion faite dans output/converted_out_without_nulls.txt"
exit 0

24
webm_to_wav.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/bash
# utilisation: bash webm_to_wav.sh
# auteur du script: tykayn contact@cipherbliss.com
echo "########### conversion des fichiers audio .webm placés dans le dossier input, vers du wav mono-piste uniquement dans le dossier input/converted_to_wav"
echo " "
cd input
mkdir already_converted
echo " "
echo "########### OK "
echo "########### fichiers webm restant dans le dossier input "
ls -l *.webm
cd ..
echo " "
COUNT_LINES_ORIGIN=$(ls -l input/*.webm |wc -l)
COUNT_LINES=$(ls -l input/converted_to_wav |wc -l)
echo "########### fichiers webm dans le dossier input: $COUNT_LINES_ORIGIN "
echo "########### fichiers wav dans le dossier input/converted_to_wav: $COUNT_LINES "
echo "########### conversion faite dans output/converted_out_without_nulls.txt"
exit 0

25
website/_foot.php Executable file
View File

@ -0,0 +1,25 @@
</main>
<section class="container footer has-background-black has-text-grey-light">
<div class="columns">
<div class="column">
<h1 class="title is-2">Confidentialité</h1>
ce site utilise youtube-dl pour récupérer la vidéo à transcrire et travailler dessus sur le serveur cette page
est installée.
Ce site ne contient aucun tracker, les fichiers audio et vidéo téléchargés sont supprimés régulièrement, aucun usage de ce que vous mettez sur ce site autre que pour transcrire de l'audio n'est opéré.
Vous pouvez aussi installer sur votre propre machine ce logiciel libre sous licence GNU affero v3.
</div>
<div class="column">
<h1 class="title is-2">Sources</h1>
<a href="https://forge.chapril.org/tykayn/transcription">
Sources: Transcription sur la forge du chapril. </a>
<br>Ceci est un logiciel libre, vous pouvez l'améliorer et examiner
son fonctionnement comme bon vous semble.
</div>
</div>
</section>
</main>
</body>
</html>

13
website/_head.php Executable file
View File

@ -0,0 +1,13 @@
<html>
<head>
<title>
Transcription vosk
</title>
<link rel="stylesheet" type="text/css" href="./bulma.min.css"/>
</head>
<body>
<main class='main'>
<div class="container">
<h1 class="title is-2">Transcription Vosk</h1>
</div>

1
website/bulma.min.css vendored Executable file

File diff suppressed because one or more lines are too long

134
website/download.php Executable file
View File

@ -0,0 +1,134 @@
<?php
include( '_head.php' );
?>
<div class="container">
<?php
/**
* récupération d'une vidéo par youtube dl et conversion
*/
/**
* @param $cmd
*
* @return bool
*/
function command_exist( $cmd ) {
$return = shell_exec( sprintf( "which %s", escapeshellarg( $cmd ) ) );
return ! empty( $return );
}
if ( isset( $_POST[ 'url' ] ) ) {
// sanitize input
$url = $_POST[ 'url' ];
$lang = isset($_POST[ 'lang' ]) ? $_POST['lang'] : 'fr';
echo "<br/>récupération de la vidéo à l'url " . $url . " ... <br>";
// if (!command_exist('youtube-dl')) {
// print '[Erreur] pas de commande youtube-dl installée sur ce serveur';
// } else {
// $uniqid = date( 'Y-M-d_' ) . time();
$uniqid = 'demo_video_tk';
// # exemple url https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
if (file_exists('../input/ydl/'.$uniqid)) {
echo "The file $filename exists";
}else{
// exec( './youtube-dl.sh uniqueid_facho https://peertube.cipherbliss.com/videos/watch/b88a9568-517c-4a49-ab07-75c79323a825', $output, $result );
exec( './youtube-dl.sh ' . $uniqid . ' ' . $url . ' ' . $lang, $output, $result );
$phrases_only = file_get_contents( '../input/ydl/' . $uniqid . '/3_without_nulls.txt' );
echo "<br/> résultat du script. <br><pre>";
var_dump( $result );
echo "</pre><br/> output du script. <br><pre>";
var_dump( $output );
echo "</pre>";
if ( $result ) {
echo '<div class="alert is-danger"> </div>
<article class="message is-danger">
<div class="message-header">
<p>Problème de script</p>
<button class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
<h2 class="title is2">
Sortie du script:
</h2><br> <br>
';
var_dump( $output );
echo '
</div>
</article>
';
include( '_foot.php' );
}
// récup du nom de fichier
echo '<article class="message is-info">
<div class="message-body">
récupération de la piste audio OK.
</div>
</article>';
echo "<br/>Conversion de la vidéo " . $uniqid . "... <br>";
}
echo '<article class="message is-success">
<div class="message-header">
<p>Succès</p>
<button class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
Vous pouvez télécharger vos fichiers.
<ul>
<li>
<a href='../input/ydl/'.$uniqid.'/4_phrases_.txt'>phrases txt</a>
</li>
</ul>
</div>
</article><br>
<article class="message is-info">
<div class="message-header">
<p>Texte avec uniquement les phrases</p>
<button class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
' . $phrases_only . '
</div>
</article>
<hr>
<br>
TODO: <br>
texte avec horodatage minute et secondes avant les phrases. <br>
fichier de sous titres au standard srt <br>
';
$dir = scandir( '../input/ydl/' . $uniqid );
var_dump( $dir );
// }
} else {
echo " <br> pas d'url envoyée. Vérifiez le formulaire. <a href='index.php'>Retour</a>";
}
// exec( './youtube-dl.sh canadien https://www.youtube.com/watch?v=w97pAEr3svc', $output, $result );
?>
</div>
<?php
include( '_foot.php' );

27
website/index.php Executable file
View File

@ -0,0 +1,27 @@
<?php
include( '_head.php' );
?>
<section class="hero is-info is-large">
<div class="hero-body">
<div class="container">
<p class="title">
Conversion d'audio ou de vidéo en texte
</p>
<p class="subtitle">
Transcrire en Français avec une URL
<form action='download.php' method='post'>
<input class="input is-block" type='text' name='url'
value="https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d">
<br>
<button class="button is-primary" type='submit'>Envoyer</button>
</form>
</div>
</p>
</div>
</section>
<?php
include( '_foot.php' );
?>

4
website/info.php Executable file
View File

@ -0,0 +1,4 @@
<?php
echo exec('website/test.sh');

21
website/log_ydl.txt Executable file
View File

@ -0,0 +1,21 @@
sam. 27 mars 2021 10:27:21 CET ###### start conversion __ essai __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
sam. 27 mars 2021 10:30:16 CET ###### start conversion __ essai __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 13:50:27 CET 2021 ###### start conversion __ essai.wav __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 14:00:20 CET 2021 ###### start conversion __ essai.wav __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 14:02:25 CET 2021 ###### start conversion __ essai __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 14:03:13 CET 2021 ###### start conversion __ essai __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 14:03:52 CET 2021 ###### start conversion __ essai __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 14:23:15 CET 2021 ###### start conversion __ batman_script __ https://peertube.cipherbliss.com/videos/watch/193545b2-3cd5-468a-b563-e17d0121e1bf
Sat Mar 27 14:23:18 CET 2021 ###### end conversion __ batman_script __ https://peertube.cipherbliss.com/videos/watch/193545b2-3cd5-468a-b563-e17d0121e1bf
Sat Mar 27 14:24:10 CET 2021 ###### start conversion __ batman_script __ https://peertube.cipherbliss.com/videos/watch/193545b2-3cd5-468a-b563-e17d0121e1bf
Sat Mar 27 14:43:29 CET 2021 ###### start conversion __ 2021-Mar-27_1616852609 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Sat Mar 27 21:48:44 CET 2021 ###### start conversion __ 2021-Mar-27_1616878123 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Tue Apr 20 17:19:12 CEST 2021 ###### start conversion __ 2021-Apr-20_1618931951 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Tue Apr 20 17:37:28 CEST 2021 ###### start conversion __ 2021-Apr-20_1618933048 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:09:49 CEST 2021 ###### start conversion __ 2021-Aug-18_1629295789 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:10:48 CEST 2021 ###### start conversion __ 2021-Aug-18_1629295848 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:12:10 CEST 2021 ###### start conversion __ 2021-Aug-18_1629295930 __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:14:13 CEST 2021 ###### start conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:15:53 CEST 2021 ###### start conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:16:15 CEST 2021 ###### start conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d
Wed Aug 18 16:17:20 CEST 2021 ###### start conversion __ demo_video_tk __ https://peertube.cipherbliss.com/videos/watch/e6a37508-042e-4d83-8598-5d36b764bb3d

5
website/run.php Executable file
View File

@ -0,0 +1,5 @@
<?php
exec( './youtube-dl.sh uniqueid_facho https://peertube.cipherbliss.com/videos/watch/b88a9568-517c-4a49-ab07-75c79323a825', $output,$result);
var_dump($output);
var_dump($result);

3
website/test.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo " coucou" > test_works.txt

1
website/test_works.txt Executable file
View File

@ -0,0 +1 @@
coucou

41
website/youtube-dl.sh Executable file
View File

@ -0,0 +1,41 @@
#!/bin/bash
touch log_ydl.txt
echo " $(date) ###### start conversion __ $1 __ $2" >> log_ydl.txt
UNIQID=$1
# mkdir -p ../input/ydl
# rm -rf ../input/ydl/$UNIQID.mp3
# rm -rf ../input/ydl/$UNIQID
URL=$2
OUTPUT="../input/ydl/$UNIQID/base.mp3"
echo " \n output : \n"
echo $OUTPUT
mkdir ../input/ydl/$UNIQID
youtube-dl --extract-audio --audio-format mp3 --audio-quality 0 --output $OUTPUT $URL --no-continue
ls -larth ../input/ydl/$UNIQID
ffmpeg -i "../input/ydl/$UNIQID/base.mp3" -ac 1 "../input/ydl/$UNIQID/mono_canal.wav"
OUT_DIR="input/ydl/$UNIQID"
mkdir $OUT_DIR
echo " $(date) ###### lancer la transcription"
pwd
ls -larth input/ydl/$UNIQID/
echo "\n"
cd ..
bash transcript.sh input/ydl/$UNIQID/mono_canal.wav
#jq .text $OUT_DIR/0_output_$FILE_NAME.json > $OUT_DIR/1_converted_$FILE_NAME.txt
# sed 's/null//g' $OUT_DIR/1_converted_$FILE_NAME.txt > $OUT_DIR/2_without_nulls_$FILE_NAME.txt
# sed 's/^ *//; s/ *$//; /^$/d' $OUT_DIR/2_without_nulls_$FILE_NAME.txt > $OUT_DIR/3_without_nulls_$FILE_NAME.txt
# sed 's/\"//g' $OUT_DIR/3_without_nulls_$FILE_NAME.txt > $OUT_DIR/4_phrases_$FILE_NAME.txt
ls -l $OUT_DIR >> log_ydl.txt
echo " $(date) ###### end conversion __ $1 __ $2" >> log_ydl.txt