def generate_speaker_sentiment_trend()

in pca-server/src/pca/pca-aws-sf-process-turn-by-turn.py [0:0]


    def generate_speaker_sentiment_trend(self, speaker, speaker_num):
        """
        Generates an entry for the "SentimentTrends" block for the given speaker, which is the overall speaker
        sentiment score and trend over the call.  For Call Analytics calls we also store the per-quarter sentiment
        data provided by Transcribe

        @param speaker: Internal name for the speaker (e.g. spk_1)
        @param speaker_num: Channel number for the speaker (only relevant for Call Analytics)
        @return:
        """

        # Our empty result block
        speaker_trend = {}

        if self.api_mode == cf.API_ANALYTICS:
            # Speaker scores / trends using Analytics data - find our speaker data
            speaker = next(key for key, value in self.analytics_channel_map.items() if value == speaker_num)
            sentiment_block = self.asr_output["ConversationCharacteristics"]["Sentiment"]

            # Store the overall score, then loop through each of the quarter's sentiment
            speaker_trend["SentimentScore"] = sentiment_block["OverallSentiment"][speaker]
            speaker_trend["SentimentPerQuarter"] = []
            for period in sentiment_block["SentimentByPeriod"]["QUARTER"][speaker]:
                speaker_trend["SentimentPerQuarter"].append(
                    {"Quarter": len(speaker_trend["SentimentPerQuarter"])+1,
                     "Score": period["Score"],
                     "BeginOffsetSecs": period["BeginOffsetMillis"]/1000.0,
                     "EndOffsetSecs": period["EndOffsetMillis"]/1000.0}
                )

            # Trend is simply FINAL-FIRST sentiment
            speaker_trend["SentimentChange"] = speaker_trend["SentimentPerQuarter"][-1]["Score"] - \
                                              speaker_trend["SentimentPerQuarter"][0]["Score"]
        else:
            # Speaker scores / trends using aggregated data from Comprehend
            # Start by initialising data structures for the sentiment total and change
            speakerTurns = 0
            sumSentiment = 0.0

            # Initialise data for the per-quarter scores
            quarter_scores = []
            for quarter in range(1,5):
                quarter_block = {
                    "Quarter": quarter,
                    "Score": 0.0,
                    "BeginOffsetSecs": 0.0,
                    "EndOffsetSecs": 0.0,
                    "datapoints": 0
                }
                quarter_scores.append(quarter_block)

            # Loop through each speech segment for this speaker
            for segment in self.speechSegmentList:
                if segment.segmentSpeaker == speaker:
                    # Increment our counter for number of speaker turns and work out our call quarter offset,
                    # and we decide which quarter a segment is in by where middle of the segment lies
                    speakerTurns += 1
                    segment_midpoint = segment.segmentStartTime + \
                                       (segment.segmentEndTime - segment.segmentStartTime) / 2
                    quarter_offset = min(floor((segment_midpoint * 4) / self.duration), 3)

                    # Update some quarter-based values that are separate from sentiment
                    quarter_scores[quarter_offset]["datapoints"] += 1
                    if quarter_scores[quarter_offset]["BeginOffsetSecs"] == 0.0:
                        quarter_scores[quarter_offset]["BeginOffsetSecs"] = segment.segmentStartTime
                    quarter_scores[quarter_offset]["EndOffsetSecs"] = segment.segmentEndTime

                    # Only really interested in Positive/Negative turns for the sentiment scores
                    if segment.segmentIsPositive or segment.segmentIsNegative:
                        # Calculate score and add it to (-ve) or subtract it from (-ve) our total
                        turn_score = segment.segmentSentimentScore
                        if segment.segmentIsNegative:
                            turn_score *= -1
                        sumSentiment += turn_score

                        # Update our quarter tracker
                        quarter_scores[quarter_offset]["Score"] += turn_score

            # Create the average score per quarter, and drop the datapoints field (as it's o longer needed)
            for quarter in quarter_scores:
                points = max(quarter["datapoints"], 1)
                quarter["Score"] /= points
                quarter.pop("datapoints", None)

            # Log our trends for this speaker
            speaker_trend["SentimentChange"] = quarter_scores[-1]["Score"] - quarter_scores[0]["Score"]
            speaker_trend["SentimentScore"] = sumSentiment / max(speakerTurns, 1)
            speaker_trend["SentimentPerQuarter"] = quarter_scores

        return speaker_trend