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