From 9c86f3bc38568e62eb4306679e0e479500c2b42b Mon Sep 17 00:00:00 2001 From: Jigsaw Date: Mon, 20 Jan 2025 23:53:20 -0500 Subject: [PATCH] Internal change GitOrigin-RevId: 37c382118924f7f7f3a16f3fec1cc171c07a5e6e --- .../summarization_subtasks/topics.test.ts | 25 +++++++- src/tasks/summarization_subtasks/topics.ts | 59 +++++++++++++++++-- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/tasks/summarization_subtasks/topics.test.ts b/src/tasks/summarization_subtasks/topics.test.ts index ebff1de..b5f3c1f 100644 --- a/src/tasks/summarization_subtasks/topics.test.ts +++ b/src/tasks/summarization_subtasks/topics.test.ts @@ -17,6 +17,10 @@ import { GroupedSummaryStats } from "../../stats_util"; import { CommentWithVoteTallies } from "../../types"; import { TopicsSummary } from "./topics"; +// Mock the model response. This mock needs to be set up to return response specific for each test. +let mockCommonGroundSummary: jest.SpyInstance; +let mockDifferencesSummary: jest.SpyInstance; + const TEST_COMMENTS: CommentWithVoteTallies[] = [ { id: "1", @@ -57,7 +61,22 @@ const TEST_COMMENTS: CommentWithVoteTallies[] = [ ]; describe("TopicsSummaryTest", () => { + beforeEach(() => { + mockCommonGroundSummary = jest.spyOn(TopicsSummary.prototype, "getCommonGroundSummary"); + mockDifferencesSummary = jest.spyOn(TopicsSummary.prototype, "getDifferencesOfOpinionSummary"); + }); + + afterEach(() => { + mockCommonGroundSummary.mockRestore(); + mockDifferencesSummary.mockRestore(); + }); it("should create a properly formatted topics summary", async () => { + // Mock the LLM calls + mockCommonGroundSummary.mockReturnValue(Promise.resolve("Some points of common ground...")); + mockDifferencesSummary.mockReturnValue( + Promise.resolve("Areas of disagreement between groups...") + ); + expect( await new TopicsSummary( new GroupedSummaryStats(TEST_COMMENTS), @@ -73,13 +92,13 @@ This topic included 2 subtopics. #### Subtopic A.1 (2 comments) -Common ground: Some points of common ground... +Common ground between groups: Some points of common ground... Differences of opinion: Areas of disagreement between groups... #### Subtopic A.2 (1 comments) -Common ground: Some points of common ground... +Common ground between groups: Some points of common ground... Differences of opinion: Areas of disagreement between groups... @@ -90,7 +109,7 @@ This topic included 1 subtopic. #### Subtopic B.1 (1 comments) -Common ground: Some points of common ground... +Common ground between groups: Some points of common ground... Differences of opinion: Areas of disagreement between groups... diff --git a/src/tasks/summarization_subtasks/topics.ts b/src/tasks/summarization_subtasks/topics.ts index 9cdc258..8b41557 100644 --- a/src/tasks/summarization_subtasks/topics.ts +++ b/src/tasks/summarization_subtasks/topics.ts @@ -15,7 +15,14 @@ // Functions for different ways to summarize Comment and Vote data. import { RecursiveSummary, resolvePromisesInParallel } from "./recursive_summarization"; -import { TopicStats, GroupedSummaryStats } from "../../stats_util"; +import { TopicStats, GroupedSummaryStats, GroupStats } from "../../stats_util"; +import { getPrompt } from "../../sensemaker_utils"; +import { Comment } from "../../types"; +import { commentCitation } from "../../validation/grounding"; + +const commonGroundInstructions = `Here are several comments sharing different opinions. Your job is to summarize these comments. Do not pretend that you hold any of these opinions. You are not a participant in this discussion. Participants in this conversation have been clustered into opinion groups. These opinion groups mostly approve of these comments. Write a concise summary of these comments that is at least one sentence and at most three sentences long. The summary should be substantiated, detailed and informative: include specific findings, requests, proposals, action items and examples, grounded in the comments. Refer to the people who made these comments as participants, not commenters. Do not talk about how strongly they approve of these comments. Use complete sentences. Do not use the passive voice. Do not use ambiguous pronouns. Be clear. Do not generate bullet points or special formatting. Do not yap.`; + +const differencesOfOpinionInstructions = `Here are several comments which generated disagreement. Your job is summarize the ideas contained in the comments. Do not pretend that you hold any of these opinions. You are not a participant in this discussion. Write a concise summary of these comments that is at least one sentence and at most three sentences long. Refer to the people who made these comments as participants, not commenters. Do not talk about how strongly they disagree on these comments. Use complete sentences. Do not use the passive voice. Do not use ambiguous pronouns. Be clear. Do not generate bullet points or special formatting. The summary should not imply that these views were agreed on by all participants. Your output should begin in the form "There was low consensus". Do not pretend that these comments were written by different people. For each sentence use a unique phrase to indicate that there was low consensus on the topic, and do not present each comment as an alternative idea. Do not yap.`; export class TopicsSummary extends RecursiveSummary { async getSummary() { @@ -90,17 +97,59 @@ ${subtopicsSummaryText} async getSubtopicSummary(subtopicStat: TopicStats): Promise { const sectionTitle: string = `${subtopicStat.name} (${subtopicStat.commentCount} comments)`; - // For now, these are mocked out... - const commonGroundSummary = "Some points of common ground..."; - const differencesSummary = "Areas of disagreement between groups..."; + const groupStats = this.input.getStatsByGroup(); + const groupNames = groupStats.map((stat: GroupStats) => { + return stat.name; + }); + + const commonGroundSummary = await this.getCommonGroundSummary(); + const differencesSummary = await this.getDifferencesOfOpinionSummary(groupNames); return Promise.resolve( `#### ${sectionTitle} -Common ground: ${commonGroundSummary} +Common ground between groups: ${commonGroundSummary} Differences of opinion: ${differencesSummary} ` ); } + + /** + * Summarizes the comments on which there was the strongest agreement between groups. + * @returns a two sentence description of similarities and differences. + */ + async getCommonGroundSummary(): Promise { + const commonGroundComments = this.input.getCommonGroundComments(); + return this.model.generateText( + getPrompt( + commonGroundInstructions, + commonGroundComments.map((comment: Comment): string => comment.text) + ) + ); + } + + /** + * Summarizes the comments on which there was the strongest disagreement between groups. + * @returns a two sentence description of similarities and differences. + */ + async getDifferencesOfOpinionSummary(groupNames: string[]): Promise { + const topDisagreeCommentsAcrossGroups = + this.input.getDifferencesBetweenGroupsComments(groupNames); + return this.model.generateText( + getPrompt( + differencesOfOpinionInstructions, + topDisagreeCommentsAcrossGroups.map((comment: Comment) => comment.text) + ) + ); + } + + /** + * Create citations for comments in the format of "[12, 43, 56]" + * @param comments the comments to use for citations + * @returns the formatted citations + */ + private getCommentCitations(comments: Comment[]): string { + return "[" + comments.map((comment) => commentCitation(comment)).join(", ") + "]"; + } }