Compare commits
1 Commits
main
...
feature/models
| Author | SHA1 | Date | |
|---|---|---|---|
| 5cb7b14705 |
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"python-envs.defaultEnvManager": "ms-python.python:conda",
|
||||||
|
"python-envs.defaultPackageManager": "ms-python.python:conda"
|
||||||
|
}
|
||||||
@@ -13,3 +13,6 @@ dependencies:
|
|||||||
- python=3.12
|
- python=3.12
|
||||||
- customtkinter
|
- customtkinter
|
||||||
- openai
|
- openai
|
||||||
|
- pip:
|
||||||
|
- vosk
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from transcription.audio import Audio
|
from transcription.audio import Audio
|
||||||
from transcription.preprocessing.audio_preprocessor import AudioPreprocessor
|
from transcription.preprocessing.audio_preprocessor import AudioPreprocessor
|
||||||
from transcription.preprocessing.splitter import Splitter
|
from transcription.preprocessing.splitter import Splitter
|
||||||
from transcription.engines.whisper import WhisperEngine
|
from transcription.engines.whisper_engine import WhisperEngine
|
||||||
from transcription.configuration import Configuration
|
from transcription.configuration import Configuration
|
||||||
|
|
||||||
# maybe inherit from AudioTranscription and rename to something like WhisperTranscription?
|
# maybe inherit from AudioTranscription and rename to something like WhisperTranscription?
|
||||||
@@ -19,11 +19,13 @@ class AudioTranscription:
|
|||||||
# self.logger = logger
|
# self.logger = logger
|
||||||
|
|
||||||
self.audio = Audio()
|
self.audio = Audio()
|
||||||
self.preprocessor = AudioPreprocessor()
|
self.preprocessor = AudioPreprocessor(16000)
|
||||||
|
|
||||||
self.splitter = Splitter(
|
self.splitter = Splitter(
|
||||||
chunkSize=config.chunkSize,
|
chunkSize=config.chunkSize,
|
||||||
batchSize=config.batchSize,
|
batchSize=config.batchSize,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.engine = WhisperEngine(
|
self.engine = WhisperEngine(
|
||||||
modelName=config.modelName,
|
modelName=config.modelName,
|
||||||
language=self.language,
|
language=self.language,
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ class Configuration:
|
|||||||
# add new models
|
# add new models
|
||||||
device: str = "cuda"
|
device: str = "cuda"
|
||||||
modelName: str = "openai/whisper-large-v2"
|
modelName: str = "openai/whisper-large-v2"
|
||||||
chunkSize: int = 30
|
chunkSize: int = 30 ## in seconds
|
||||||
batchSize: int = 16
|
batchSize: int = 16 ## in batches
|
||||||
dataType: str = "torch.float16"
|
dataType: str = "torch.float16"
|
||||||
|
|
||||||
_dtype_map = {
|
_dtype_map = {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import torch
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
class BaseEngine(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def loadModel(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def unloadModel(self) -> None:
|
||||||
|
pass
|
||||||
@@ -1,30 +1,18 @@
|
|||||||
import torch
|
from transcription.engines.BaseEngine import BaseEngine
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
class BaseEngine(ABC):
|
class BatchSTTEngine(BaseEngine):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
modelName: str,
|
modelName: str,
|
||||||
language: str,
|
language: str,
|
||||||
dType: torch.dtype,
|
dType: torch.dtype,
|
||||||
device: str
|
device: str
|
||||||
):
|
) -> None:
|
||||||
self.modelName = modelName
|
self.modelName = modelName
|
||||||
self.device = device
|
self.device = device
|
||||||
self.language = language
|
self.language = language
|
||||||
self.dType = dType
|
self.dType = dType
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def loadModel(self) -> None:
|
def transcribeBatch(self) -> None:
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def unloadModel(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def transcribeBatch(
|
|
||||||
self,
|
|
||||||
batch
|
|
||||||
) -> str:
|
|
||||||
pass
|
pass
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from transcription.engines.BaseEngine import BaseEngine
|
||||||
|
|
||||||
|
class StreamingSTTEngine(BaseEngine):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
...
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
from transcription.engines.BaseEngine import BaseEngine
|
||||||
|
import wave, json
|
||||||
|
from vosk import Model, KaldiRecognizer
|
||||||
|
|
||||||
|
"""
|
||||||
|
import wave
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from multiprocessing.dummy import Pool
|
||||||
|
from vosk import Model, KaldiRecognizer
|
||||||
|
|
||||||
|
model = Model("en-us")
|
||||||
|
|
||||||
|
def recognize(line):
|
||||||
|
uid, fn = line.split()
|
||||||
|
wf = wave.open(fn, "rb")
|
||||||
|
rec = KaldiRecognizer(model, wf.getframerate())
|
||||||
|
|
||||||
|
text = ""
|
||||||
|
while True:
|
||||||
|
data = wf.readframes(1000)
|
||||||
|
if len(data) == 0:
|
||||||
|
break
|
||||||
|
if rec.AcceptWaveform(data):
|
||||||
|
jres = json.loads(rec.Result())
|
||||||
|
text = text + " " + jres["text"]
|
||||||
|
jres = json.loads(rec.FinalResult())
|
||||||
|
text = text + " " + jres["text"]
|
||||||
|
return uid + text
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p = Pool(8)
|
||||||
|
texts = p.map(recognize, open(sys.argv[1], encoding="utf-8").readlines())
|
||||||
|
print ("\n".join(texts))
|
||||||
|
|
||||||
|
main()
|
||||||
|
"""
|
||||||
|
|
||||||
|
class VoskEngine(BaseEngine):
|
||||||
|
TARGET_SAMPLING_RATE = 16000
|
||||||
|
|
||||||
|
def loadModel(self) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
def unloadModel(self) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
def transcribeBatch(
|
||||||
|
self,
|
||||||
|
batch,
|
||||||
|
) -> str:
|
||||||
|
...
|
||||||
@@ -4,9 +4,11 @@ import torch
|
|||||||
import gc
|
import gc
|
||||||
from transformers import WhisperForConditionalGeneration, WhisperProcessor
|
from transformers import WhisperForConditionalGeneration, WhisperProcessor
|
||||||
|
|
||||||
from transcription.engines.base_engine import BaseEngine
|
from transcription.engines.BatchSTT import BatchSTT
|
||||||
|
|
||||||
|
class WhisperEngine(BatchSTT):
|
||||||
|
TARGET_SAMPLING_RATE = 16000
|
||||||
|
|
||||||
class WhisperEngine(BaseEngine):
|
|
||||||
def loadModel(self) -> None:
|
def loadModel(self) -> None:
|
||||||
self.processor = WhisperProcessor.from_pretrained(self.modelName)
|
self.processor = WhisperProcessor.from_pretrained(self.modelName)
|
||||||
self.model = WhisperForConditionalGeneration.from_pretrained(
|
self.model = WhisperForConditionalGeneration.from_pretrained(
|
||||||
@@ -31,7 +33,7 @@ class WhisperEngine(BaseEngine):
|
|||||||
|
|
||||||
inputs = self.processor(
|
inputs = self.processor(
|
||||||
batch,
|
batch,
|
||||||
sampling_rate=16000,
|
sampling_rate=self.TARGET_SAMPLING_RATE,
|
||||||
return_tensors="pt",
|
return_tensors="pt",
|
||||||
padding=True,
|
padding=True,
|
||||||
)
|
)
|
||||||
@@ -8,6 +8,9 @@ class AudioPreprocessor:
|
|||||||
# def __init__(self, model):
|
# def __init__(self, model):
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
def __init__(self, target_sr: int) -> None:
|
||||||
|
self.TARGET_SAMPLING_RATE = target_sr
|
||||||
|
|
||||||
def _resample(
|
def _resample(
|
||||||
self,
|
self,
|
||||||
audio: Audio
|
audio: Audio
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import torch
|
import torch
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from logging import Logger
|
||||||
|
|
||||||
|
# TODO: add logging here
|
||||||
class Splitter:
|
class Splitter:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
chunkSize: int,
|
chunkSize: int,
|
||||||
batchSize: int,
|
batchSize: int,
|
||||||
|
# logger: Logger
|
||||||
) -> None:
|
) -> None:
|
||||||
self.chunkSize = chunkSize * 16000 # 16 kHz after resampling
|
self.chunkSize = chunkSize * 16000 # 16 kHz after resampling
|
||||||
self.batchSize = batchSize
|
self.batchSize = batchSize
|
||||||
@@ -19,7 +22,7 @@ class Splitter:
|
|||||||
chunksCount = (totalSamples + self.chunkSize - 1) // self.chunkSize
|
chunksCount = (totalSamples + self.chunkSize - 1) // self.chunkSize
|
||||||
|
|
||||||
chunks: List = []
|
chunks: List = []
|
||||||
# tqdm or something here?
|
# tqdm for logger or something here?
|
||||||
for chunkNum in range(chunksCount):
|
for chunkNum in range(chunksCount):
|
||||||
start = chunkNum * self.chunkSize
|
start = chunkNum * self.chunkSize
|
||||||
end = min((chunkNum + 1) * self.chunkSize, totalSamples)
|
end = min((chunkNum + 1) * self.chunkSize, totalSamples)
|
||||||
@@ -34,11 +37,9 @@ class Splitter:
|
|||||||
chunks: List,
|
chunks: List,
|
||||||
) -> List:
|
) -> List:
|
||||||
batches: List = []
|
batches: List = []
|
||||||
|
|
||||||
for i in range(0, len(chunks), self.batchSize):
|
for i in range(0, len(chunks), self.batchSize):
|
||||||
batch = chunks[i : i + self.batchSize]
|
batch = chunks[i : i + self.batchSize]
|
||||||
batches.append(batch)
|
batches.append(batch)
|
||||||
|
|
||||||
return batches
|
return batches
|
||||||
|
|
||||||
def split(
|
def split(
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
class Time:
|
||||||
|
|
||||||
Reference in New Issue
Block a user