fixed a bug
This commit is contained in:
@@ -152,10 +152,11 @@ curl -X POST http://127.0.0.1:8001/v1/audio/transcriptions \
|
|||||||
|
|
||||||
### 断句规则
|
### 断句规则
|
||||||
|
|
||||||
`sentence_api` 不以 Whisper 返回的 segment 直接作为句子,而是把每个 segment 的文本
|
`sentence_api` 不以 Whisper 返回的 segment 直接作为句子:文本会跨 segment 累积,
|
||||||
按句号(`.`)拆成一句句,句号即句子结束。若转写服务支持词级时间戳
|
只有碰到句号(`.`)或问号(`?`)才算一句结束;Whisper 在没有标点处断开的
|
||||||
|
segment 会自动合并成同一句。若转写服务支持词级时间戳
|
||||||
(`timestamp_granularities[]=word`,Whisper/Speaches 支持),句子的结束时间用
|
(`timestamp_granularities[]=word`,Whisper/Speaches 支持),句子的结束时间用
|
||||||
句号所在单词的时间戳;不支持时自动按文字长度在 segment 内估算,请求失败会回退为
|
标点所在单词的时间戳;不支持时自动按文字长度在 segment 内估算,请求失败会回退为
|
||||||
不带词级时间戳的普通请求。MOSS 不支持该参数时同样自动回退,不影响转写。
|
不带词级时间戳的普通请求。MOSS 不支持该参数时同样自动回退,不影响转写。
|
||||||
|
|
||||||
## 3. 部署 API
|
## 3. 部署 API
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from .config import Settings
|
|||||||
from .generate_boundaries import ALGORITHM_VERSION, make_entry
|
from .generate_boundaries import ALGORITHM_VERSION, make_entry
|
||||||
from .models import SentenceBoundary, SentenceBoundaryDocument
|
from .models import SentenceBoundary, SentenceBoundaryDocument
|
||||||
from .repository import VideoRepository
|
from .repository import VideoRepository
|
||||||
from .transcription import Transcript, Transcriber, split_segment_by_periods
|
from .transcription import Transcript, Transcriber, split_sentences_at_punctuation
|
||||||
|
|
||||||
|
|
||||||
MOSS_ALGORITHM_VERSION = "moss-period-v2"
|
MOSS_ALGORITHM_VERSION = "moss-period-v2"
|
||||||
@@ -107,8 +107,7 @@ def document_from_transcript(
|
|||||||
samples, sample_rate = decode_audio_mono(audio_path)
|
samples, sample_rate = decode_audio_mono(audio_path)
|
||||||
sentences: List[SentenceBoundary] = []
|
sentences: List[SentenceBoundary] = []
|
||||||
previous_end = 0
|
previous_end = 0
|
||||||
for segment in sorted(transcript.segments, key=lambda item: (item.start_seconds, item.end_seconds)):
|
for sentence_segment in split_sentences_at_punctuation(transcript.segments):
|
||||||
for sentence_segment in split_segment_by_periods(segment):
|
|
||||||
start_ms = max(previous_end, int(round(sentence_segment.start_seconds * 1000)))
|
start_ms = max(previous_end, int(round(sentence_segment.start_seconds * 1000)))
|
||||||
end_ms = min(duration_ms, int(round(sentence_segment.end_seconds * 1000)))
|
end_ms = min(duration_ms, int(round(sentence_segment.end_seconds * 1000)))
|
||||||
if not sentence_segment.text.strip() or end_ms <= start_ms:
|
if not sentence_segment.text.strip() or end_ms <= start_ms:
|
||||||
|
|||||||
@@ -22,48 +22,61 @@ def _silence(seconds: float) -> np.ndarray:
|
|||||||
return np.zeros(int(seconds * SAMPLE_RATE))
|
return np.zeros(int(seconds * SAMPLE_RATE))
|
||||||
|
|
||||||
|
|
||||||
def test_document_from_transcript_splits_sentences_at_periods(tmp_path):
|
def test_document_from_transcript_splits_sentences_at_punctuation(tmp_path):
|
||||||
samples = np.concatenate(
|
samples = np.concatenate(
|
||||||
[
|
[
|
||||||
_speech(2.0),
|
_speech(8.0),
|
||||||
_silence(0.2),
|
_speech(1.5),
|
||||||
_speech(2.0),
|
_speech(10.5),
|
||||||
_silence(0.2),
|
_speech(4.0),
|
||||||
_speech(1.6),
|
|
||||||
]
|
]
|
||||||
).astype(np.float32)
|
).astype(np.float32)
|
||||||
wav = tmp_path / "audio.wav"
|
wav = tmp_path / "audio.wav"
|
||||||
wav.write_bytes(_wav_bytes(samples, SAMPLE_RATE))
|
wav.write_bytes(_wav_bytes(samples, SAMPLE_RATE))
|
||||||
transcript = Transcript(
|
transcript = Transcript(
|
||||||
text="Hello world. Good day everyone. Nice to meet you.",
|
text=(
|
||||||
|
"So I've been single for about four years now and I find it hard to meet "
|
||||||
|
"a guy especially in California. I've tried dating apps, I've met friends "
|
||||||
|
"through friends, I've done online dating and I just feel like most of the "
|
||||||
|
"guys that I meet aren't serious about a relationship."
|
||||||
|
),
|
||||||
segments=[
|
segments=[
|
||||||
TranscriptionSegment(
|
TranscriptionSegment(
|
||||||
start_seconds=0.0,
|
start_seconds=0.0,
|
||||||
end_seconds=2.0,
|
end_seconds=8.0,
|
||||||
text="Hello world.",
|
text=(
|
||||||
words=[
|
"So I've been single for about four years now and I find it hard "
|
||||||
WordTimestamp(0.0, 0.6, "Hello"),
|
"to meet a guy especially in"
|
||||||
WordTimestamp(0.7, 1.5, "world."),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
TranscriptionSegment(
|
TranscriptionSegment(
|
||||||
start_seconds=2.2,
|
start_seconds=8.0,
|
||||||
end_seconds=5.5,
|
end_seconds=9.5,
|
||||||
text="Good day everyone. Nice to meet you.",
|
text="California.",
|
||||||
words=[
|
words=[WordTimestamp(8.0, 9.5, "California.")],
|
||||||
WordTimestamp(2.2, 2.8, "Good"),
|
),
|
||||||
WordTimestamp(2.9, 3.5, "day"),
|
TranscriptionSegment(
|
||||||
WordTimestamp(3.6, 4.2, "everyone."),
|
start_seconds=9.5,
|
||||||
WordTimestamp(4.4, 4.9, "Nice"),
|
end_seconds=20.0,
|
||||||
WordTimestamp(5.0, 5.5, "you."),
|
text=(
|
||||||
],
|
"I've tried dating apps, I've met friends through friends, "
|
||||||
|
"I've done online dating"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=20.0,
|
||||||
|
end_seconds=24.0,
|
||||||
|
text=(
|
||||||
|
"and I just feel like most of the guys that I meet aren't serious "
|
||||||
|
"about a relationship."
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
document = document_from_transcript(
|
document = document_from_transcript(
|
||||||
video_hash=VIDEO_HASH,
|
video_hash=VIDEO_HASH,
|
||||||
duration_ms=6000,
|
duration_ms=24000,
|
||||||
transcript=transcript,
|
transcript=transcript,
|
||||||
language="en",
|
language="en",
|
||||||
audio_path=wav,
|
audio_path=wav,
|
||||||
@@ -71,14 +84,18 @@ def test_document_from_transcript_splits_sentences_at_periods(tmp_path):
|
|||||||
|
|
||||||
assert document.algorithm_version == MOSS_ALGORITHM_VERSION
|
assert document.algorithm_version == MOSS_ALGORITHM_VERSION
|
||||||
assert [sentence.text for sentence in document.sentences] == [
|
assert [sentence.text for sentence in document.sentences] == [
|
||||||
"Hello world.",
|
(
|
||||||
"Good day everyone.",
|
"So I've been single for about four years now and I find it hard to meet "
|
||||||
"Nice to meet you.",
|
"a guy especially in California."
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"I've tried dating apps, I've met friends through friends, I've done "
|
||||||
|
"online dating and I just feel like most of the guys that I meet aren't "
|
||||||
|
"serious about a relationship."
|
||||||
|
),
|
||||||
]
|
]
|
||||||
assert document.sentences[0].start_ms == 0
|
assert document.sentences[0].start_ms == 0
|
||||||
assert document.sentences[0].end_ms == 1500
|
assert document.sentences[0].end_ms == 9500
|
||||||
assert document.sentences[1].start_ms == 2200
|
assert document.sentences[1].start_ms == 9500
|
||||||
assert document.sentences[1].end_ms == 4200
|
assert document.sentences[1].end_ms == 24000
|
||||||
assert document.sentences[2].start_ms == 4200
|
|
||||||
assert document.sentences[2].end_ms == 5500
|
|
||||||
assert all(sentence.reference_speech_duration_ms > 0 for sentence in document.sentences)
|
assert all(sentence.reference_speech_duration_ms > 0 for sentence in document.sentences)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from sentence_api.transcription import (
|
|||||||
_parse_json_segments,
|
_parse_json_segments,
|
||||||
_plan_chunks,
|
_plan_chunks,
|
||||||
_parse_word_timestamps,
|
_parse_word_timestamps,
|
||||||
split_segment_by_periods,
|
split_sentences_at_punctuation,
|
||||||
_wav_bytes,
|
_wav_bytes,
|
||||||
_wav_duration_seconds,
|
_wav_duration_seconds,
|
||||||
)
|
)
|
||||||
@@ -195,7 +195,59 @@ def test_parse_word_timestamps_ignores_invalid_entries():
|
|||||||
assert _parse_word_timestamps("nope") is None
|
assert _parse_word_timestamps("nope") is None
|
||||||
|
|
||||||
|
|
||||||
def test_split_segment_by_periods_uses_word_timestamps():
|
def test_split_sentences_merges_segments_without_punctuation():
|
||||||
|
segments = [
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=0.0,
|
||||||
|
end_seconds=8.0,
|
||||||
|
text=(
|
||||||
|
"So I've been single for about four years now and I find it hard "
|
||||||
|
"to meet a guy especially in"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=8.0,
|
||||||
|
end_seconds=9.5,
|
||||||
|
text="California.",
|
||||||
|
words=[WordTimestamp(8.0, 9.5, "California.")],
|
||||||
|
),
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=9.5,
|
||||||
|
end_seconds=20.0,
|
||||||
|
text=(
|
||||||
|
"I've tried dating apps, I've met friends through friends, "
|
||||||
|
"I've done online dating"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=20.0,
|
||||||
|
end_seconds=24.0,
|
||||||
|
text=(
|
||||||
|
"and I just feel like most of the guys that I meet aren't serious "
|
||||||
|
"about a relationship."
|
||||||
|
),
|
||||||
|
words=[WordTimestamp(20.0, 24.0, "relationship.")],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
sentences = split_sentences_at_punctuation(segments)
|
||||||
|
assert [(s.text, s.start_seconds, s.end_seconds) for s in sentences] == [
|
||||||
|
(
|
||||||
|
"So I've been single for about four years now and I find it hard to meet "
|
||||||
|
"a guy especially in California.",
|
||||||
|
0.0,
|
||||||
|
9.5,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"I've tried dating apps, I've met friends through friends, I've done "
|
||||||
|
"online dating and I just feel like most of the guys that I meet aren't "
|
||||||
|
"serious about a relationship.",
|
||||||
|
9.5,
|
||||||
|
24.0,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_split_sentences_uses_word_timestamps_within_segment():
|
||||||
segment = TranscriptionSegment(
|
segment = TranscriptionSegment(
|
||||||
start_seconds=0.0,
|
start_seconds=0.0,
|
||||||
end_seconds=4.0,
|
end_seconds=4.0,
|
||||||
@@ -209,7 +261,7 @@ def test_split_segment_by_periods_uses_word_timestamps():
|
|||||||
WordTimestamp(3.9, 4.0, "you."),
|
WordTimestamp(3.9, 4.0, "you."),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
sentences = split_segment_by_periods(segment)
|
sentences = split_sentences_at_punctuation([segment])
|
||||||
assert [(s.text, s.start_seconds, s.end_seconds) for s in sentences] == [
|
assert [(s.text, s.start_seconds, s.end_seconds) for s in sentences] == [
|
||||||
("Hello world.", 0.0, 1.5),
|
("Hello world.", 0.0, 1.5),
|
||||||
("Good day.", 1.5, 3.2),
|
("Good day.", 1.5, 3.2),
|
||||||
@@ -217,27 +269,46 @@ def test_split_segment_by_periods_uses_word_timestamps():
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_split_segment_by_periods_falls_back_to_proportional():
|
def test_split_sentences_splits_at_question_marks():
|
||||||
segment = TranscriptionSegment(
|
segment = TranscriptionSegment(
|
||||||
start_seconds=10.0,
|
start_seconds=0.0,
|
||||||
end_seconds=20.0,
|
end_seconds=10.0,
|
||||||
text="First sentence. Second sentence. Third.",
|
text="Really? Wait a minute. What about now?",
|
||||||
)
|
)
|
||||||
sentences = split_segment_by_periods(segment)
|
sentences = split_sentences_at_punctuation([segment])
|
||||||
assert [s.text for s in sentences] == [
|
assert [s.text for s in sentences] == [
|
||||||
"First sentence.",
|
"Really?",
|
||||||
"Second sentence.",
|
"Wait a minute.",
|
||||||
"Third.",
|
"What about now?",
|
||||||
|
]
|
||||||
|
assert sentences[0].start_seconds == 0.0
|
||||||
|
assert sentences[0].end_seconds == sentences[1].start_seconds
|
||||||
|
assert sentences[1].end_seconds == sentences[2].start_seconds
|
||||||
|
assert sentences[2].end_seconds == 10.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_split_sentences_falls_back_to_proportional():
|
||||||
|
segments = [
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=10.0, end_seconds=14.0, text="This is the first"
|
||||||
|
),
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=14.0,
|
||||||
|
end_seconds=18.0,
|
||||||
|
text="sentence. And this is the second one.",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
sentences = split_sentences_at_punctuation(segments)
|
||||||
|
assert [s.text for s in sentences] == [
|
||||||
|
"This is the first sentence.",
|
||||||
|
"And this is the second one.",
|
||||||
]
|
]
|
||||||
assert sentences[0].start_seconds == 10.0
|
assert sentences[0].start_seconds == 10.0
|
||||||
assert sentences[1].start_seconds == sentences[0].end_seconds
|
assert sentences[0].end_seconds == sentences[1].start_seconds
|
||||||
assert sentences[2].end_seconds == 20.0
|
assert sentences[1].end_seconds == 18.0
|
||||||
assert sentences[0].end_seconds > 10.0
|
|
||||||
assert sentences[1].end_seconds < 20.0
|
|
||||||
assert sentences[0].end_seconds < sentences[1].end_seconds
|
|
||||||
|
|
||||||
|
|
||||||
def test_split_segment_by_periods_falls_back_when_word_ends_are_invalid():
|
def test_split_sentences_falls_back_when_word_ends_are_invalid():
|
||||||
segment = TranscriptionSegment(
|
segment = TranscriptionSegment(
|
||||||
start_seconds=0.0,
|
start_seconds=0.0,
|
||||||
end_seconds=2.0,
|
end_seconds=2.0,
|
||||||
@@ -247,30 +318,37 @@ def test_split_segment_by_periods_falls_back_when_word_ends_are_invalid():
|
|||||||
WordTimestamp(2.6, 3.0, "Two."),
|
WordTimestamp(2.6, 3.0, "Two."),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
sentences = split_segment_by_periods(segment)
|
sentences = split_sentences_at_punctuation([segment])
|
||||||
assert [s.text for s in sentences] == ["One.", "Two."]
|
assert [s.text for s in sentences] == ["One.", "Two."]
|
||||||
assert sentences[0].end_seconds == sentences[1].start_seconds
|
assert sentences[0].end_seconds == sentences[1].start_seconds
|
||||||
assert sentences[1].end_seconds == 2.0
|
assert sentences[1].end_seconds == 2.0
|
||||||
|
|
||||||
|
|
||||||
def test_split_segment_by_periods_keeps_segment_without_period():
|
def test_split_sentences_keeps_incomplete_tail_as_sentence():
|
||||||
segment = TranscriptionSegment(
|
segment = TranscriptionSegment(
|
||||||
start_seconds=1.0, end_seconds=2.0, text="no period here"
|
start_seconds=1.0, end_seconds=2.0, text="no period here"
|
||||||
)
|
)
|
||||||
assert split_segment_by_periods(segment) == [segment]
|
sentences = split_sentences_at_punctuation([segment])
|
||||||
|
assert [(s.text, s.start_seconds, s.end_seconds) for s in sentences] == [
|
||||||
|
("no period here", 1.0, 2.0)
|
||||||
|
]
|
||||||
|
assert split_sentences_at_punctuation([]) == []
|
||||||
|
|
||||||
|
|
||||||
def test_split_segment_by_periods_handles_ellipsis_and_dots_only():
|
def test_split_sentences_handles_ellipsis_and_dots_only():
|
||||||
segment = TranscriptionSegment(
|
segment = TranscriptionSegment(
|
||||||
start_seconds=0.0,
|
start_seconds=0.0,
|
||||||
end_seconds=2.0,
|
end_seconds=2.0,
|
||||||
text="Wait... What? ...",
|
text="Wait... What? ...",
|
||||||
)
|
)
|
||||||
sentences = split_segment_by_periods(segment)
|
sentences = split_sentences_at_punctuation([segment])
|
||||||
assert [s.text for s in sentences] == ["Wait...", "What? ..."]
|
assert [s.text for s in sentences] == ["Wait...", "What?"]
|
||||||
assert sentences[0].start_seconds == 0.0
|
assert sentences[0].start_seconds == 0.0
|
||||||
assert sentences[0].end_seconds == sentences[1].start_seconds
|
assert sentences[0].end_seconds == sentences[1].start_seconds
|
||||||
assert sentences[1].end_seconds == 2.0
|
assert sentences[1].end_seconds == 2.0
|
||||||
|
assert split_sentences_at_punctuation(
|
||||||
|
[TranscriptionSegment(0.0, 1.0, "...")]
|
||||||
|
) == []
|
||||||
|
|
||||||
|
|
||||||
def test_post_audio_requests_word_timestamps_and_falls_back(monkeypatch):
|
def test_post_audio_requests_word_timestamps_and_falls_back(monkeypatch):
|
||||||
|
|||||||
@@ -239,55 +239,75 @@ def _parse_word_timestamps(raw_words) -> Optional[List[WordTimestamp]]:
|
|||||||
return words or None
|
return words or None
|
||||||
|
|
||||||
|
|
||||||
_PERIOD_BOUNDARY = re.compile(r"\.+")
|
_PUNCTUATION_BOUNDARY = re.compile(r"[.?]+")
|
||||||
|
|
||||||
|
|
||||||
def split_segment_by_periods(
|
def split_sentences_at_punctuation(
|
||||||
segment: TranscriptionSegment,
|
segments: List[TranscriptionSegment],
|
||||||
) -> List[TranscriptionSegment]:
|
) -> List[TranscriptionSegment]:
|
||||||
"""Split one whisper segment into sentences at periods (".")."""
|
"""Merge whisper segments and cut sentences at periods/question marks.
|
||||||
|
|
||||||
|
Whisper's own segment breaks often fall mid-sentence, so text is accumulated
|
||||||
|
across segments and a sentence is only closed once the accumulated text
|
||||||
|
reaches a period or a question mark.
|
||||||
|
"""
|
||||||
|
sentences: List[TranscriptionSegment] = []
|
||||||
|
pieces: List[str] = []
|
||||||
|
start_seconds: Optional[float] = None
|
||||||
|
last_segment_end: Optional[float] = None
|
||||||
|
|
||||||
|
def flush(end_seconds: float) -> None:
|
||||||
|
nonlocal pieces, start_seconds
|
||||||
|
text = " ".join(piece for piece in pieces if piece).strip()
|
||||||
|
if text and start_seconds is not None and end_seconds > start_seconds:
|
||||||
|
sentences.append(
|
||||||
|
TranscriptionSegment(
|
||||||
|
start_seconds=start_seconds,
|
||||||
|
end_seconds=end_seconds,
|
||||||
|
text=text,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pieces = []
|
||||||
|
start_seconds = None
|
||||||
|
|
||||||
|
for segment in sorted(
|
||||||
|
segments, key=lambda item: (item.start_seconds, item.end_seconds)
|
||||||
|
):
|
||||||
text = segment.text.strip()
|
text = segment.text.strip()
|
||||||
if not text:
|
if not text:
|
||||||
return []
|
continue
|
||||||
pieces: List[str] = []
|
if not pieces:
|
||||||
|
start_seconds = segment.start_seconds
|
||||||
|
seg_pieces: List[str] = []
|
||||||
cursor = 0
|
cursor = 0
|
||||||
for match in _PERIOD_BOUNDARY.finditer(text):
|
for match in _PUNCTUATION_BOUNDARY.finditer(text):
|
||||||
piece = text[cursor:match.end()].strip()
|
piece = text[cursor:match.end()].strip()
|
||||||
if piece.strip(".").strip():
|
|
||||||
pieces.append(piece)
|
|
||||||
cursor = match.end()
|
cursor = match.end()
|
||||||
|
if piece.strip(".?").strip():
|
||||||
|
seg_pieces.append(piece)
|
||||||
tail = text[cursor:].strip()
|
tail = text[cursor:].strip()
|
||||||
if tail:
|
if tail:
|
||||||
pieces.append(tail)
|
seg_pieces.append(tail)
|
||||||
if len(pieces) <= 1:
|
if not seg_pieces:
|
||||||
return [segment] if pieces else []
|
continue
|
||||||
ends = _sentence_end_seconds(segment, pieces)
|
lengths = [len(piece) for piece in seg_pieces]
|
||||||
sub_segments: List[TranscriptionSegment] = []
|
ends: List[float] = []
|
||||||
start = segment.start_seconds
|
if segment.words and len(segment.words) >= len(seg_pieces):
|
||||||
for piece, end in zip(pieces, ends):
|
ends = _word_boundary_ends(segment, lengths)
|
||||||
if end > start:
|
if not _valid_boundaries(segment, ends):
|
||||||
sub_segments.append(
|
ends = []
|
||||||
TranscriptionSegment(
|
if not ends:
|
||||||
start_seconds=start,
|
ends = _proportional_ends(segment, lengths)
|
||||||
end_seconds=end,
|
last_segment_end = segment.end_seconds
|
||||||
text=piece,
|
for index, piece in enumerate(seg_pieces):
|
||||||
speaker=segment.speaker,
|
pieces.append(piece)
|
||||||
)
|
if piece[-1] in ".?":
|
||||||
)
|
end_seconds = ends[index] if index < len(ends) else segment.end_seconds
|
||||||
start = end
|
flush(end_seconds)
|
||||||
return sub_segments
|
start_seconds = end_seconds
|
||||||
|
if pieces:
|
||||||
|
flush(last_segment_end if last_segment_end is not None else start_seconds)
|
||||||
def _sentence_end_seconds(
|
return sentences
|
||||||
segment: TranscriptionSegment, pieces: List[str]
|
|
||||||
) -> List[float]:
|
|
||||||
lengths = [len(piece) for piece in pieces]
|
|
||||||
total = sum(lengths)
|
|
||||||
if segment.words and len(segment.words) >= len(pieces):
|
|
||||||
word_ends = _word_boundary_ends(segment, lengths)
|
|
||||||
if _valid_boundaries(segment, word_ends):
|
|
||||||
return word_ends + [segment.end_seconds]
|
|
||||||
return _proportional_ends(segment, lengths) + [segment.end_seconds]
|
|
||||||
|
|
||||||
|
|
||||||
def _word_boundary_ends(
|
def _word_boundary_ends(
|
||||||
|
|||||||
Reference in New Issue
Block a user