Форматирование строк из массива объектов в единственную строку - PullRequest
0 голосов
/ 21 апреля 2020

Я использую Google Speech-to-Text API для преобразования аудио файла в текст. Он может идентифицировать ораторов, что действительно круто, но он форматирует информацию так, что у меня возникают проблемы. Вот их документы о разделении динамиков.

Моя цель - создать единую строку, разделяющую строки по динамикам, что-то вроде этого:

Speaker1: Hello Tom
Speaker2: Howdy
Speaker1: How was your weekend

Если Я посылаю аудио файл для расшифровки, я получаю что-то вроде этого:

wordsObjects =
[
  {
    startTime: { seconds: '1'},
    endTime: { seconds: '1'},
    word: 'Hello',
    speakerTag: 1
  },
  {
    startTime: { seconds: '2'},
    endTime: { seconds: '2'},
    word: 'Tom',
    speakerTag: 1
  },
]

Конечно, для каждого слова есть объект, я просто хочу сэкономить место. Все, что Том говорит в этом примере, должно быть представлено как speakerTag: 2

Вот самое близкое, что я получил до сих пор:

  const unformattedTranscript = wordsObjects.map((currentWord, idx, arr) => {
    if (arr[idx + 1]) {
      if (currentWord.speakerTag === arr[idx + 1].speakerTag) {
        return [currentWord.word, arr[idx + 1].word];
      } else {
        return ["SPEAKER CHANGE"];
      }
    }
  });

  const formattedTranscript = unformattedTranscript.reduce(
    (acc, wordArr, idx, arr) => {
      if (arr[idx + 1]) {
        if (wordArr[wordArr.length - 1] === arr[idx + 1][0]) {
          wordArr.pop();
          acc.push(wordArr.concat(arr[idx + 1]));
        } else {
          acc.push(["\n"]);
        }
      }
      return acc;
    },
    []
  );

Это решение не работает, если говорящий говорит более двух слова подряд. Мне удалось полностью запутаться в этом, поэтому я бы с удовольствием подтолкнул в правильном направлении.

Заранее благодарен за любой совет.

Ответы [ 3 ]

1 голос
/ 21 апреля 2020

Вы можете добавить chunkWhile функцию генератора . Разделите элементы на части, если тег динамика одинаков, а затем преобразуйте каждый фрагмент в строку.

function* chunkWhile(iterable, fn) {
  const iterator = iterable[Symbol.iterator]();
  let {done, value: valueA} = iterator.next();
  if (done) return;

  let chunk = Array.of(valueA);
  for (const valueB of iterator) {
    if (fn(valueA, valueB)) {
      chunk.push(valueB);
    } else {
      yield chunk;
      chunk = Array.of(valueB);
    }
    valueA = valueB;
  }
  yield chunk;
}

const wordsObjects = [
  { word: 'Hello'  , speakerTag: 1 },
  { word: 'Tom'    , speakerTag: 1 },
  { word: 'Howdy'  , speakerTag: 2 },
  { word: 'How'    , speakerTag: 1 },
  { word: 'was'    , speakerTag: 1 },
  { word: 'your'   , speakerTag: 1 },
  { word: 'weekend', speakerTag: 1 },
];

const chunkGenerator = chunkWhile(
  wordsObjects,
  (a, b) => a.speakerTag == b.speakerTag,
);

let string = "";
for (const wordsObjects of chunkGenerator) {
  const speakerTag = wordsObjects[0].speakerTag;
  const words      = wordsObjects.map(({word}) => word).join(" ");
  
  string += `Speaker${speakerTag}: ${words}\n`;
}

console.log(string);

Если вам когда-либо понадобится преобразовать генератор в массив, вы можете сделать Array.from(generator) или [...generator].

0 голосов
/ 21 апреля 2020

Вот как бы я это сделал, используя редуктор:

  const formattedTranscript = wordsObjects.reduce((accumulator, currentValue) => {

    // check if same speaker (continue on the same line)
    if(accumulator.length > 0)
    {
        const lastItem = accumulator[accumulator.length -1];
        if(lastItem.speakerTag === currentValue.speakerTag) {
          lastItem.text += " " + currentValue.word;
          return accumulator;
        }
    }

    // new line (new speaker)
    accumulator.push({
        speakerTag: currentValue.speakerTag, 
        text: currentValue.word 
    });

    return accumulator;
}, []);
0 голосов
/ 21 апреля 2020

Я думаю, вы слишком усложняете вещи. Вы можете просто перебирать массив слов и отслеживать текущий тэг динамика. Всякий раз, когда текущий тег слова изменяется, вы можете добавить новую строку (а если она не изменилась - добавить текущее слово к текущей строке). Вот пример:

const stringifyDialog = (words) => {
    let currSpeakerTag // number | undefined
    let lines = [] // Array<[number, string]>, where number is speaker tag and string is the line

    for (let {speakerTag, word} of words) {
        if (speakerTag !== currSpeakerTag) {
            currSpeakerTag = speakerTag
            lines.push([speakerTag, word])
        } else {
            lines[lines.length - 1][1] += ` ${word}`
        }
    }

    return lines.map(([speakerTag, line]) => `Speaker${speakerTag}: ${line}`).join('\n')
}

При заданном вводе

const wordsObjects =
[
  {
    word: 'Hello',
    speakerTag: 1
  },
  {
    word: 'Tom',
    speakerTag: 1
  },
  {
    word: 'Howdy',
    speakerTag: 2
  },
  {
    word: 'How',
    speakerTag: 1
  },
  {
    word: 'was',
    speakerTag: 1
  },
  {
    word: 'your',
    speakerTag: 1
  },
  {
    word: 'weekend',
    speakerTag: 1
  },
]

это даст

"Speaker1: Hello Tom
Speaker2: Howdy
Speaker1: How was your weekend"
...