语音到文本 - 将说话者标签映射到JSON响应中的相应记录

时间:2018-06-17 20:44:46

标签: python json python-3.x speech-to-text

每隔一段时间就会出现一段JSON数据,这些数据可能需要数小时才能从中提取所需信息。我有一个从Speech To Text API引擎生成的以下JSON响应。

它显示了每个单词的成绩单,发音,以及会话中每个发言者speaker 0speaker 2的时间戳和发言人标签。

   {
    "results": [
        {
            "alternatives": [
                {
                    "timestamps": [
                        [
                            "the",
                            6.18,
                            6.63
                        ],
                        [
                            "weather",
                            6.63,
                            6.95
                        ],
                        [
                            "is",
                            6.95,
                            7.53
                        ],
                        [
                            "sunny",
                            7.73,
                            8.11
                        ],
                        [
                            "it's",
                            8.21,
                            8.5
                        ],
                        [
                            "time",
                            8.5,
                            8.66
                        ],
                        [
                            "to",
                            8.66,
                            8.81
                        ],
                        [
                            "sip",
                            8.81,
                            8.99
                        ],
                        [
                            "in",
                            8.99,
                            9.02
                        ],
                        [
                            "some",
                            9.02,
                            9.25
                        ],
                        [
                            "cold",
                            9.25,
                            9.32
                        ],
                        [
                            "beer",
                            9.32,
                            9.68
                        ]
                    ],
                    "confidence": 0.812,
                    "transcript": "the weather is sunny it's time to sip in some cold beer "
                }
            ],
            "final": "True"
        },
        {
            "alternatives": [
                {
                    "timestamps": [
                        [
                            "sure",
                            10.52,
                            10.88
                        ],
                        [
                            "that",
                            10.92,
                            11.19
                        ],
                        [
                            "sounds",
                            11.68,
                            11.82
                        ],
                        [
                            "like",
                            11.82,
                            12.11
                        ],
                        [
                            "a",
                            12.32,
                            12.96
                        ],
                        [
                            "plan",
                            12.99,
                            13.8
                        ]
                    ],
                    "confidence": 0.829,
                    "transcript": "sure that sounds like a plan"
                }
            ],
            "final": "True"
        }
    ],
    "result_index":0,
    "speaker_labels": [
        {
            "from": 6.18,
            "to": 6.63,
            "speaker": 0,
            "confidence": 0.475,
            "final": "False"
        },
        {
            "from": 6.63,
            "to": 6.95,
            "speaker": 0,
            "confidence": 0.475,
            "final": "False"
        },
        {
            "from": 6.95,
            "to": 7.53,
            "speaker": 0,
            "confidence": 0.475,
            "final": "False"
        },
        {
            "from": 7.73,
            "to": 8.11,
            "speaker": 0,
            "confidence": 0.499,
            "final": "False"
        },
        {
            "from": 8.21,
            "to": 8.5,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 8.5,
            "to": 8.66,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 8.66,
            "to": 8.81,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 8.81,
            "to": 8.99,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 8.99,
            "to": 9.02,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 9.02,
            "to": 9.25,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 9.25,
            "to": 9.32,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 9.32,
            "to": 9.68,
            "speaker": 0,
            "confidence": 0.472,
            "final": "False"
        },
        {
            "from": 10.52,
            "to": 10.88,
            "speaker": 2,
            "confidence": 0.441,
            "final": "False"
        },
        {
            "from": 10.92,
            "to": 11.19,
            "speaker": 2,
            "confidence": 0.364,
            "final": "False"
        },
        {
            "from": 11.68,
            "to": 11.82,
            "speaker": 2,
            "confidence": 0.372,
            "final": "False"
        },
        {
            "from": 11.82,
            "to": 12.11,
            "speaker": 2,
            "confidence": 0.372,
            "final": "False"
        },
        {
            "from": 12.32,
            "to": 12.96,
            "speaker": 2,
            "confidence": 0.383,
            "final": "False"
        },
        {
            "from": 12.99,
            "to": 13.8,
            "speaker": 2,
            "confidence": 0.428,
            "final": "False"
        }
    ]
}

原谅缩进问题(如果有的话),但JSON是有效的,我一直试图用相应的扬声器标签映射每个抄本。

我想要类似下面的东西。上面的JSON大概是20,000行,它是根据时间戳和时间戳提取扬声器标签的噩梦。单词话语并将其与transcript一起放在一起。

[
    {
        "transcript": "the weather is sunny it's time to sip in some cold beer ",
        "speaker" : 0
    },
    {
        "transcript": "sure that sounds like a plan",
        "speaker" : 2
    }

]  

到目前为止我尝试了什么: JSON数据存储在名为example.json的文件中。我已经能够将每个单词及其相应的时间戳和扬声器标签放在元组列表中(参见下面的输出):

import json
# with open('C:\\Users\\%USERPROFILE%\\Desktop\\example.json', 'r') as f:
    # data = json.load(f)

l1 = []
l2 = []
l3 = []

for i in data['results']:
    for j in i['alternatives'][0]['timestamps']:
        l1.append(j)

for m in data['speaker_labels']:
     l2.append(m)

for q in l1:
    for n in l2:
        if q[1]==n['from']:
            l3.append((q[0],n['speaker'], q[1], q[2]))
print(l3)

这给出了输出:

 [('the', 0, 6.18, 6.63),
 ('weather', 0, 6.63, 6.95),
 ('is', 0, 6.95, 7.53),
 ('sunny', 0, 7.73, 8.11),
 ("it's", 0, 8.21, 8.5),
 ('time', 0, 8.5, 8.66),
 ('to', 0, 8.66, 8.81),
 ('sip', 0, 8.81, 8.99),
 ('in', 0, 8.99, 9.02),
 ('some', 0, 9.02, 9.25),
 ('cold', 0, 9.25, 9.32),
 ('beer', 0, 9.32, 9.68),
 ('sure', 2, 10.52, 10.88),
 ('that', 2, 10.92, 11.19),
 ('sounds', 2, 11.68, 11.82),
 ('like', 2, 11.82, 12.11),
 ('a', 2, 12.32, 12.96),
 ('plan', 2, 12.99, 13.8)]

但现在我不确定如何根据时间戳比较和#34;桶"每组单词再次用其扬声器标签形成成绩单。

我还设法将成绩单放在列表中,但现在如何从上面的列表中提取每个成绩单的发言人标签。不幸的是,发言人标签speaker 0speaker 2适用于每个单词,我希望他们会为每个transcript代替。

for i in data['results']:
    l4.append(i['alternatives'][0]['transcript'])

这给出了输出:

["the weather is sunny it's time to sip in some cold beer ",'sure that sounds like a plan']

我已尽力解释问题,但我愿意接受任何反馈意见,并会在必要时进行更改。此外,我很确定有更好的方法来解决这个问题,而不是制作几个列表,非常感谢任何帮助。

对于更大的数据集,请参阅pastebin。我希望这个数据集可以在性能基准测试中发挥作用。我可以在可用时或在需要时提供更大的数据集。

当我处理大型JSON数据时,性能是一个重要因素,同样准确地实现重叠转录中的扬声器隔离是另一个要求。

3 个答案:

答案 0 :(得分:1)

使用熊猫,这就是我刚刚解决的方法。

假设数据存储在名为data

的字典中
import pandas as pd

labels = pd.DataFrame.from_records(data['speaker_labels'])

transcript_tstamps = pd.DataFrame.from_records(
    [t for r in data['results'] 
       for a in r['alternatives'] 
       for t in a['timestamps']], 
    columns=['word', 'from', 'to']
)
# this list comprehension more-efficiently de-nests the dictionary into
# records that can be used to create a DataFrame

df = labels.merge(transcript_tstamps)
# produces a dataframe of speakers to words based on timestamps from & to
# since I knew I wanted to merge on the from & to columns, 
# I named the columns thus when I created the transcript_tstamps data frame
# like this:
    confidence  final   from  speaker     to     word
0        0.475  False   6.18        0   6.63      the
1        0.475  False   6.63        0   6.95  weather
2        0.475  False   6.95        0   7.53       is
3        0.499  False   7.73        0   8.11    sunny
4        0.472  False   8.21        0   8.50     it's
5        0.472  False   8.50        0   8.66     time
6        0.472  False   8.66        0   8.81       to
7        0.472  False   8.81        0   8.99      sip
8        0.472  False   8.99        0   9.02       in
9        0.472  False   9.02        0   9.25     some
10       0.472  False   9.25        0   9.32     cold
11       0.472  False   9.32        0   9.68     beer
12       0.441  False  10.52        2  10.88     sure
13       0.364  False  10.92        2  11.19     that
14       0.372  False  11.68        2  11.82   sounds
15       0.372  False  11.82        2  12.11     like
16       0.383  False  12.32        2  12.96        a
17       0.428  False  12.99        2  13.80     plan

将说话人和单词数据合并后,有必要将同一说话人的连续单词分组在一起以得出当前说话人。例如,如果扬声器阵列看起来像[2,2,2,2,0,0,0,2,2,2,0,0,0,0],我们需要将前四个{ }},然后是接下来的三个2,然后是三个0,然后是其余的2

0对数据进行排序,然后为此设置一个名为['from', 'to']的虚拟变量,如下所示:

current_speaker

从这里开始,按df = df.sort_values(['from', 'to']) df['current_speaker'] = (df.speaker.shift() != df.speaker).cumsum() 分组,将单词聚合为一个句子,然后转换为json。有一些其他的重命名来修复输出的json键

current_speaker

要在记录开始/结束时添加其他数据,可以将from / to的最小值/最大值添加到分组依据

transcripts = df.groupby('current_speaker').agg({
   'word': lambda x: ' '.join(x),
   'speaker': min
}).rename(columns={'word': 'transcript'})
transcripts[['speaker', 'transcript']].to_json(orient='records')
# produces the following output (indentation added by me for legibility):
'[{"speaker":0,
  "transcript":"the weather is sunny it\'s time to sip in some cold beer"},    
 {"speaker":2,
  "transcript":"sure that sounds like a plan"}]'

此外,(尽管这不适用于该示例数据集)您也许应该为每个时间片选择具有最高置信度的替代项。

答案 1 :(得分:0)

这是我使用JS尝试过的方法
使用python

看看是否对您有用
var resultTimestampLen = 0;

arrLen = JSON.parse(sTot_resuts.results.length);
for(var i = 0; i<arrLen; i++){

    speakerLablefrom = sTot_resuts.speaker_labels[resultTimestampLen].from;

    speakerLabelto = sTot_resuts.speaker_labels[resultTimestampLen].to;

    speakerId = sTot_resuts.speaker_labels[resultTimestampLen].speaker;


    var findSpeaker = new Array();
    findSpeaker = sTot_resuts.results[i].alternatives[0].timestamps[0];

    var timeStampFrom = findSpeaker[1];

    var timeStampto = findSpeaker[2];


      if(timeStampFrom === speakerLablefrom && timeStampto === speakerLabelto){
        console.log('Speaker '+sTot_resuts.speaker_labels[resultTimestampLen].speaker + ' ' + sTot_resuts.results[i].alternatives[0].transcript);
        var resultsTimestamp = new Array();
        resultsTimestamp = sTot_resuts.results[i].alternatives[0].timestamps.length;

        resultTimestampLen = resultsTimestamp+resultTimestampLen;
      }else{
        console.log('resultTimestampLen '+resultTimestampLen + 'speakerLablefrom '+speakerLablefrom + 'speakerLabelto '+speakerLabelto + 'timeStampFrom '+timeStampFrom + 'timeStampto '+timeStampto);
      }
}

答案 2 :(得分:-1)

我这样做是通过根据时间戳将单词放入字典中,然后使他们与讲话者匹配:

times = {}
for r in data['results']:
    for word in r['alternatives'][0]['timestamps']:
        times[(word[1], word[2])] = word[0]

transcripts = {}
for r in data['speaker_labels']:
    speaker = r['speaker']
    if speaker in transcripts:
        transcripts[speaker].append(times[(r['from'], r['to'])])
    else:
        transcripts[speaker] = [times[(r['from'], r['to'])]]

print([{'speaker': k, 'transcript': ' '.join(transcripts[k])} for k in transcripts])

它在示例中运行了大约12.34秒,提供了1,000,000次,因此希望它足够快地满足您的要求。