ТранскрибаторТранскрибатор
Практическая инструкция

Время речи каждого говорящего: как посчитать интервалы CSV без двойного счёта

Сумма и объединение временных интервалов одного говорящего через Python. Проверка start и end, перекрытий и ограничений оценки времени речи.

Транскрибатор
ЗАПИСЬПЛАН РАБОТЫПроверьте границы речиОбъедините перекрытияУкажите правила расчётаПроверить результатОТ СЛОВ К РЕЗУЛЬТАТУ
Работа с реальной записьюНаглядный учебный примерШаблон для копирования
1Проверьте границы речи2Объедините перекрытия3Укажите правила расчёта
Границы речи дают время; объединение интервалов убирает повторный счёт одного участка.

Сначала определите, что считается речью

По тексту с одним стартовым таймкодом нельзя точно определить длительность реплики. Следующая метка может включать паузу, а начало другого говорящего не всегда означает конец первого. Для расчёта нужны проверенные начало и конец каждого отрезка и правила включения пауз.

В этой статье start и end — секунды от начала одной записи. Поле speaker обозначает подтверждённую метку человека. Если ваш CSV содержит только text и timecode, сначала подготовьте интервальную разметку по аудио. Не утверждайте, что сервис автоматически выдал точные границы, если такой результат не проверен. Текстовую основу можно получить через Транскрибатор.

Различайте сумму и объединённую длительность

У одного говорящего отрезки 0–5 и 4–8 секунд имеют сумму 9 секунд, но покрывают 8 секунд записи. Общая часть 4–5 не должна считаться дважды. Отрезок 10–12 добавляет ещё 2: итог объединения равен 10 секундам, простая сумма — 11.

Если говорят два человека одновременно, этот момент входит во время обоих. Сумма длительностей людей может быть больше длительности аудио. Это не обязательно ошибка. Не превращайте долю времени в оценку участия или качества ответа: короткая реплика может содержать ключевое решение, а длинный отрезок — чтение документа.

Посчитайте оба показателя и сохраните проверку

Подготовьте speech-intervals.csv с колонками speaker,start,end. В учебной схеме используется десятичная точка: 12.5, а не строка 00:12,500. Сохраните код как speaker_time.py и выполните python speaker_time.py. Результат speaker-duration.csv создаётся в режиме x.

Код запрещает отрицательное начало, конец не позже начала, пустую метку и бесконечные значения. Сначала сортируются интервалы каждого говорящего; соприкасающиеся и перекрывающиеся объединяются. Округление происходит только при записи итогов до трёх знаков. Все группы хранятся в памяти.

import csv, math
from pathlib import Path
from collections import defaultdict

groups = defaultdict(list)
with Path("speech-intervals.csv").open(encoding="utf-8-sig", newline="") as file:
    reader = csv.DictReader(file)
    fields = reader.fieldnames or []
    if not {"speaker", "start", "end"} <= set(fields) or len(fields) != len(set(fields)):
        raise ValueError("Проверьте колонки")
    for row in reader:
        if None in row or any(v is None for v in row.values()):
            raise ValueError("Неполные записи или лишние поля")
        speaker = row["speaker"]
        a, b = float(row["start"]), float(row["end"])
        if not speaker.strip() or not all(map(math.isfinite, (a,b))) or not 0 <= a < b:
            raise ValueError("Неверный говорящий или интервал")
        groups[speaker].append((a,b))

def union_duration(intervals):
    merged = []
    for a,b in sorted(intervals):
        if merged and a <= merged[-1][1]:
            merged[-1][1] = max(merged[-1][1], b)
        else:
            merged.append([a,b])
    return sum(b-a for a,b in merged)

with Path("speaker-duration.csv").open("x", encoding="utf-8-sig", newline="") as file:
    writer = csv.writer(file)
    writer.writerow(["speaker", "intervals", "sum_seconds", "union_seconds"])
    for speaker, intervals in groups.items():
        writer.writerow([speaker, len(intervals), round(sum(b-a for a,b in intervals), 3),
                         round(union_duration(intervals), 3)])
print("Результат описывает размеченные интервалы, не важность выступлений")

Проверьте расхождения по аудио

Сравните sum_seconds и union_seconds. Большое расхождение у одного человека — повод изучить дубли интервалов, неверное имя или перекрывающуюся разметку. Совпадение показателей не подтверждает точность границ. Прослушайте начало, конец и спорные смены говорящих, а также проверьте, что end не выходит за фактический конец источника.

Для таблицы с разными интервью сначала выполните разделение по источнику. Числа секунд разных записей не принадлежат одному таймлайну. При ошибках колонок поможет проверка CSV.

В отчёте укажите, включены ли паузы внутри реплики, как обработана неразборчивая речь и кто проверял метки. Алгоритм не выделяет речь из аудио, не определяет личность и не исправляет диаризацию. Он лишь считает уже заданные интервалы по явному правилу.

Учебный пример

Учебный расчёт для одного говорящего

Вымышленные интервалы используют общий отсчёт одной записи.

ИнтервалыПростая суммаОбъединение
0–5 и 4–89 с8 с
Плюс 10–1211 с10 с
Другой говорящий 4–6Считается отдельноПерекрытие людей допустимо
РазметкаНачало и конецПроверить по аудиоРасчётОбъединение одногочеловекаУбрать двойной счётВыводВремя размеченныхинтерваловУказать ограничения
Время характеризует выбранное правило разметки, а не ценность сказанного.

Все числа учебные. При неизвестных границах не подставляйте предполагаемую длительность как измеренный результат.

Паспорт расчёта времени речи

Рабочая заготовкаВыделите и скопируйте
Аудиофайл: [источник]
CSV и версия: [имя]
Единицы: секунды
Правило пауз: [описание]
Метки людей: [проверка]
Выход за конец записи: [проверка]
Сумма и объединение: [расхождения]
Спорные границы: [таймкоды]
Ограничения результата: [описание]

Частые вопросы

Достаточно стартовых таймкодов?

Нет. Нужны проверенные начало и конец каждого учитываемого интервала.

Почему время всех людей больше записи?

При одновременной речи один участок может входить во время нескольких людей.

Объединение исправляет диаризацию?

Нет. Оно считает интервалы внутри предоставленных меток.

Длиннее говорил — лучше участвовал?

Такого вывода длительность сама по себе не позволяет.