def build_call_loudness_charts()

in python/ts-to-word.py [0:0]


def build_call_loudness_charts(document, speech_segments, interruptions, quiet_time, talk_time, temp_files):
    """
    Creates the call loudness charts for each caller, which we also overlay sentiment on
    :param document: Word document structure to write the graphics into
    :param speech_segments: Call transcript structures
    :param interruptions: Call speaker interruption structures
    :param quiet_time: Call non-talk time structures
    :param talk_time: Call talk time structures
    :param temp_files: List of temporary files for later deletion (includes our graph)
    """

    # Start with a new single-column section
    document.add_section(WD_SECTION.CONTINUOUS)
    section_ptr = document.sections[-1]._sectPr
    cols = section_ptr.xpath('./w:cols')[0]
    cols.set(qn('w:num'), '1')
    document.add_paragraph()
    write_custom_text_header(document, "Conversation Volume Levels with Sentiment and Interruptions")

    # Initialise our loudness structures
    secsLoudAgent = []
    dbLoudAgent = []
    secsLoudCaller = []
    dbLoudCaller = []

    # Work through each conversation turn, extracting timestamp/decibel values as we go
    for segment in speech_segments:
        this_second = int(segment.segmentStartTime)
        # Each segment has a loudness score per second or part second
        for score in segment.segmentLoudnessScores:
            # This can be set to NONE, which causes errors later
            if score is None:
                score = 0.0
            # Track the Agent loudness
            if segment.segmentSpeaker == "Agent":
                secsLoudAgent.append(this_second)
                dbLoudAgent.append(score)
            # Track the Caller loudness
            else:
                secsLoudCaller.append(this_second)
                dbLoudCaller.append(score)
            this_second += 1
    agentLoudness = {"Seconds": secsLoudAgent, "dB": dbLoudAgent}
    callerLoudness = {"Seconds": secsLoudCaller, "dB": dbLoudCaller}

    # Work out our final talk "second", as we need both charts to line up, but
    # be careful as there may just be one speaker in the Call Analytics output
    if talk_time["DetailsByParticipant"]["AGENT"]["TotalTimeMillis"] == 0:
        final_second = max(secsLoudCaller)
        max_decibel = max(dbLoudCaller)
        haveAgent = False
        haveCaller = True
        plotRows = 1
    elif talk_time["DetailsByParticipant"]["CUSTOMER"]["TotalTimeMillis"] == 0:
        final_second = max(secsLoudAgent)
        max_decibel = max(dbLoudAgent)
        haveAgent = True
        haveCaller = False
        plotRows = 1
    else:
        final_second = max(max(secsLoudAgent), max(secsLoudCaller))
        max_decibel = max(max(dbLoudAgent), max(dbLoudCaller))
        haveAgent = True
        haveCaller = True
        plotRows = 2

    # Add some headroom to our decibel limit to give space for "interruption" markers
    max_decibel_headroom = (int(max_decibel / 10) + 2) * 10

    # Create a dataset for interruptions, which needs to be in the background on both charts
    intSecs = []
    intDb = []
    for speaker in interruptions["InterruptionsByInterrupter"]:
        for entry in interruptions["InterruptionsByInterrupter"][speaker]:
            start = int(entry["BeginOffsetMillis"] / 1000)
            end = int(entry["EndOffsetMillis"] / 1000)
            for second in range(start, end+1):
                intSecs.append(second)
                intDb.append(max_decibel_headroom)
    intSegments = {"Seconds": intSecs, "dB": intDb}

    # Create a dataset for non-talk time, which needs to be in the background on both charts
    quietSecs = []
    quietdB = []
    for quiet_period in quiet_time["Instances"]:
        start = int(quiet_period["BeginOffsetMillis"] / 1000)
        end = int(quiet_period["EndOffsetMillis"] / 1000)
        for second in range(start, end + 1):
            quietSecs.append(second)
            quietdB.append(max_decibel_headroom)
    quietSegments = {"Seconds": quietSecs, "dB": quietdB}

    # Either speaker may be missing, so we cannot assume this is a 2-row or 1-row plot
    # We want a 2-row figure, one row per speaker, but with the interruptions on the background
    fig, ax = plt.subplots(nrows=plotRows, ncols=1, figsize=(12, 2.5 * plotRows))
    if haveAgent:
        if haveCaller:
            build_single_loudness_chart(ax[0], agentLoudness, intSegments, quietSegments, speech_segments,
                                        final_second, max_decibel_headroom, "Agent", False, True)
            build_single_loudness_chart(ax[1], callerLoudness, intSegments, quietSegments, speech_segments,
                                        final_second, max_decibel_headroom, "Customer", True, False)
        else:
            build_single_loudness_chart(ax, agentLoudness, intSegments, quietSegments, speech_segments,
                                        final_second, max_decibel_headroom, "Agent", True, True)
    elif haveCaller:
        build_single_loudness_chart(ax, callerLoudness, intSegments, quietSegments, speech_segments,
                                    final_second, max_decibel_headroom, "Customer", True, True)

    # Add the chart to our document
    chart_file_name = "./" + "volume.png"
    fig.savefig(chart_file_name, facecolor="aliceblue")
    temp_files.append(chart_file_name)
    document.add_picture(chart_file_name, width=Cm(17))
    document.paragraphs[-1].alignment = WD_ALIGN_PARAGRAPH.LEFT
    plt.clf()