Merge remote-tracking branch 'contrib/fix-sentencesegmenter'
This commit is contained in:
commit
6e0f1dda25
3 changed files with 54 additions and 30 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -127,3 +127,6 @@ dmypy.json
|
||||||
|
|
||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
|
*.wav
|
||||||
|
run_*.sh
|
||||||
|
|
@ -87,11 +87,20 @@ class OnlineASRProcessor:
|
||||||
buffer_trimming=("segment", 15),
|
buffer_trimming=("segment", 15),
|
||||||
logfile=sys.stderr,
|
logfile=sys.stderr,
|
||||||
):
|
):
|
||||||
"""asr: WhisperASR object
|
"""
|
||||||
tokenize_method: sentence tokenizer function for the target language. Must be a callable and behaves like the one of MosesTokenizer. It can be None, if "segment" buffer trimming option is used, then tokenizer is not used at all.
|
Initialize OnlineASRProcessor.
|
||||||
("segment", 15)
|
|
||||||
buffer_trimming: a pair of (option, seconds), where option is either "sentence" or "segment", and seconds is a number. Buffer is trimmed if it is longer than "seconds" threshold. Default is the most recommended option.
|
Args:
|
||||||
logfile: where to store the log.
|
asr: WhisperASR object
|
||||||
|
tokenize_method: Sentence tokenizer function for the target language.
|
||||||
|
Must be a function that takes a list of text as input like MosesSentenceSplitter.
|
||||||
|
Can be None if using "segment" buffer trimming option.
|
||||||
|
buffer_trimming: Tuple of (option, seconds) where:
|
||||||
|
- option: Either "sentence" or "segment"
|
||||||
|
- seconds: Number of seconds threshold for buffer trimming
|
||||||
|
Default is ("segment", 15)
|
||||||
|
logfile: File to store logs
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.asr = asr
|
self.asr = asr
|
||||||
self.tokenize = tokenize_method
|
self.tokenize = tokenize_method
|
||||||
|
|
@ -142,7 +151,7 @@ class OnlineASRProcessor:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
prompt, non_prompt = self.prompt()
|
prompt, non_prompt = self.prompt()
|
||||||
logger.debug(f"PROMPT: {prompt}")
|
logger.debug(f"PROMPT(previous): {prompt}")
|
||||||
logger.debug(f"CONTEXT: {non_prompt}")
|
logger.debug(f"CONTEXT: {non_prompt}")
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"transcribing {len(self.audio_buffer)/self.SAMPLING_RATE:2.2f} seconds from {self.buffer_time_offset:2.2f}"
|
f"transcribing {len(self.audio_buffer)/self.SAMPLING_RATE:2.2f} seconds from {self.buffer_time_offset:2.2f}"
|
||||||
|
|
@ -200,21 +209,26 @@ class OnlineASRProcessor:
|
||||||
def chunk_completed_sentence(self):
|
def chunk_completed_sentence(self):
|
||||||
if self.commited == []:
|
if self.commited == []:
|
||||||
return
|
return
|
||||||
|
|
||||||
import pdb; pdb.set_trace()
|
|
||||||
raw_text = self.asr.sep.join([s[2] for s in self.commited])
|
raw_text = self.asr.sep.join([s[2] for s in self.commited])
|
||||||
logger.debug(f"COMPLETED SENTENCE: {raw_text}")
|
logger.debug(f"COMPLETED SENTENCE: {raw_text}")
|
||||||
sents = self.words_to_sentences(self.commited)
|
sents = self.words_to_sentences(self.commited)
|
||||||
for s in sents:
|
|
||||||
logger.debug(f"\t\tSENT: {s}")
|
|
||||||
|
|
||||||
if len(sents) < 2:
|
if len(sents) < 2:
|
||||||
|
logger.debug(f"[Sentence-segmentation] no sentence segmented.")
|
||||||
return
|
return
|
||||||
while len(sents) > 2:
|
|
||||||
sents.pop(0)
|
|
||||||
|
|
||||||
|
identified_sentence= "\n - ".join([f"{s[0]*1000:.0f}-{s[1]*1000:.0f} {s[2]}" for s in sents])
|
||||||
|
logger.debug(f"[Sentence-segmentation] identified sentences:\n - {identified_sentence}")
|
||||||
|
|
||||||
|
|
||||||
# we will continue with audio processing at this timestamp
|
# we will continue with audio processing at this timestamp
|
||||||
chunk_at = sents[-2][1]
|
chunk_at = sents[-2][1]
|
||||||
|
|
||||||
logger.debug(f"--- sentence chunked at {chunk_at:2.2f}")
|
logger.debug(f"[Sentence-segmentation]: sentence will be chunked at {chunk_at:2.2f}")
|
||||||
self.chunk_at(chunk_at)
|
self.chunk_at(chunk_at)
|
||||||
|
|
||||||
def chunk_completed_segment(self, res):
|
def chunk_completed_segment(self, res):
|
||||||
|
|
@ -253,7 +267,8 @@ class OnlineASRProcessor:
|
||||||
|
|
||||||
cwords = [w for w in words]
|
cwords = [w for w in words]
|
||||||
t = self.asr.sep.join(o[2] for o in cwords)
|
t = self.asr.sep.join(o[2] for o in cwords)
|
||||||
s = self.tokenize(t)
|
logger.debug(f"[Sentence-segmentation] Raw Text: {t}")
|
||||||
|
s = self.tokenize([t])
|
||||||
out = []
|
out = []
|
||||||
while s:
|
while s:
|
||||||
beg = None
|
beg = None
|
||||||
|
|
@ -278,7 +293,7 @@ class OnlineASRProcessor:
|
||||||
"""
|
"""
|
||||||
o = self.transcript_buffer.complete()
|
o = self.transcript_buffer.complete()
|
||||||
f = self.to_flush(o)
|
f = self.to_flush(o)
|
||||||
logger.debug(f"last, noncommited: {f[0]*1000:.0f}-{f[1]*1000:.0f}: {f[2]}")
|
logger.debug(f"last, noncommited: {f[0]*1000:.0f}-{f[1]*1000:.0f}: {f[2][0]*1000:.0f}-{f[1]*1000:.0f}: {f[2]}")
|
||||||
self.buffer_time_offset += len(self.audio_buffer) / 16000
|
self.buffer_time_offset += len(self.audio_buffer) / 16000
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ def create_tokenizer(lan):
|
||||||
lan
|
lan
|
||||||
in "as bn ca cs de el en es et fi fr ga gu hi hu is it kn lt lv ml mni mr nl or pa pl pt ro ru sk sl sv ta te yue zh".split()
|
in "as bn ca cs de el en es et fi fr ga gu hi hu is it kn lt lv ml mni mr nl or pa pl pt ro ru sk sl sv ta te yue zh".split()
|
||||||
):
|
):
|
||||||
from mosestokenizer import MosesTokenizer
|
from mosestokenizer import MosesSentenceSplitter
|
||||||
|
|
||||||
return MosesTokenizer(lan)
|
return MosesSentenceSplitter(lan)
|
||||||
|
|
||||||
# the following languages are in Whisper, but not in wtpsplit:
|
# the following languages are in Whisper, but not in wtpsplit:
|
||||||
if (
|
if (
|
||||||
|
|
@ -204,6 +204,7 @@ def backend_factory(args):
|
||||||
|
|
||||||
# Create the tokenizer
|
# Create the tokenizer
|
||||||
if args.buffer_trimming == "sentence":
|
if args.buffer_trimming == "sentence":
|
||||||
|
|
||||||
tokenizer = create_tokenizer(tgt_language)
|
tokenizer = create_tokenizer(tgt_language)
|
||||||
else:
|
else:
|
||||||
tokenizer = None
|
tokenizer = None
|
||||||
|
|
@ -235,10 +236,12 @@ def asr_factory(args, logfile=sys.stderr):
|
||||||
online = online_factory(args, asr, tokenizer, logfile=logfile)
|
online = online_factory(args, asr, tokenizer, logfile=logfile)
|
||||||
return asr, online
|
return asr, online
|
||||||
|
|
||||||
def set_logging(args, logger, other="_server"):
|
def set_logging(args, logger, others=[]):
|
||||||
logging.basicConfig(format="%(levelname)s\t%(message)s") # format='%(name)s
|
logging.basicConfig(format="%(levelname)s\t%(message)s") # format='%(name)s
|
||||||
logger.setLevel(args.log_level)
|
logger.setLevel(args.log_level)
|
||||||
logging.getLogger("whisper_online" + other).setLevel(args.log_level)
|
|
||||||
|
for other in others:
|
||||||
|
logging.getLogger(other).setLevel(args.log_level)
|
||||||
|
|
||||||
|
|
||||||
# logging.getLogger("whisper_online_server").setLevel(args.log_level)
|
# logging.getLogger("whisper_online_server").setLevel(args.log_level)
|
||||||
|
|
@ -275,7 +278,7 @@ if __name__ == "__main__":
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# reset to store stderr to different file stream, e.g. open(os.devnull,"w")
|
# reset to store stderr to different file stream, e.g. open(os.devnull,"w")
|
||||||
logfile = sys.stderr
|
logfile = None # sys.stderr
|
||||||
|
|
||||||
if args.offline and args.comp_unaware:
|
if args.offline and args.comp_unaware:
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|
@ -287,7 +290,7 @@ if __name__ == "__main__":
|
||||||
# logging.basicConfig(format='whisper-%(levelname)s:%(name)s: %(message)s',
|
# logging.basicConfig(format='whisper-%(levelname)s:%(name)s: %(message)s',
|
||||||
# level=getattr(logging, args.log_level))
|
# level=getattr(logging, args.log_level))
|
||||||
|
|
||||||
set_logging(args, logger)
|
set_logging(args, logger,others=["src.whisper_streaming.online_asr"])
|
||||||
|
|
||||||
audio_path = args.audio_path
|
audio_path = args.audio_path
|
||||||
|
|
||||||
|
|
@ -320,15 +323,18 @@ if __name__ == "__main__":
|
||||||
if now is None:
|
if now is None:
|
||||||
now = time.time() - start
|
now = time.time() - start
|
||||||
if o[0] is not None:
|
if o[0] is not None:
|
||||||
print(
|
log_string = f"{now*1000:1.0f}, {o[0]*1000:1.0f}-{o[1]*1000:1.0f} ({(now-o[1]):+1.0f}s): {o[2]}"
|
||||||
"%1.4f %1.0f %1.0f %s" % (now * 1000, o[0] * 1000, o[1] * 1000, o[2]),
|
|
||||||
file=logfile,
|
logger.debug(
|
||||||
flush=True,
|
log_string
|
||||||
)
|
|
||||||
print(
|
|
||||||
"%1.4f %1.0f %1.0f %s" % (now * 1000, o[0] * 1000, o[1] * 1000, o[2]),
|
|
||||||
flush=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if logfile is not None:
|
||||||
|
print(
|
||||||
|
log_string,
|
||||||
|
file=logfile,
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# No text, so no output
|
# No text, so no output
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue