From 6a29060aefd4fa449d64e618e7102f733ed36448 Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Thu, 2 May 2024 19:44:59 +0100 Subject: [PATCH 1/6] chore: remove ai summary from discussion thread --- .../helpers/addAIGeneratedContentToThreads.ts | 26 +++---------------- .../mutations/helpers/handleCompletedStage.ts | 2 +- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/packages/server/graphql/mutations/helpers/addAIGeneratedContentToThreads.ts b/packages/server/graphql/mutations/helpers/addAIGeneratedContentToThreads.ts index 50b385c6a8f..fa513232f98 100644 --- a/packages/server/graphql/mutations/helpers/addAIGeneratedContentToThreads.ts +++ b/packages/server/graphql/mutations/helpers/addAIGeneratedContentToThreads.ts @@ -1,11 +1,9 @@ -import {AIExplainer} from '../../../../client/types/constEnums' import {PARABOL_AI_USER_ID} from '../../../../client/utils/constants' import getRethink from '../../../database/rethinkDriver' import Comment from '../../../database/types/Comment' import DiscussStage from '../../../database/types/DiscussStage' import {convertHtmlToTaskContent} from '../../../utils/draftjs/convertHtmlToTaskContent' import {DataLoaderWorker} from '../../graphql' -import {getFeatureTier} from '../../types/helpers/getFeatureTier' export const buildCommentContentBlock = ( title: string, @@ -28,33 +26,17 @@ export const createAIComment = (discussionId: string, content: string, order: nu const addAIGeneratedContentToThreads = async ( stages: DiscussStage[], meetingId: string, - teamId: string, dataLoader: DataLoaderWorker ) => { - const [r, groups, team] = await Promise.all([ + const [r, groups] = await Promise.all([ getRethink(), - dataLoader.get('retroReflectionGroupsByMeetingId').load(meetingId), - dataLoader.get('teams').loadNonNull(teamId) + dataLoader.get('retroReflectionGroupsByMeetingId').load(meetingId) ]) - const commentPromises = stages.map(async ({discussionId, reflectionGroupId}, idx) => { + const commentPromises = stages.map(async ({discussionId, reflectionGroupId}) => { const group = groups.find((group) => group.id === reflectionGroupId) - if (!group?.summary && !group?.discussionPromptQuestion) return + if (!group?.discussionPromptQuestion) return const comments: Comment[] = [] - if (group.summary) { - const topicSummaryExplainerText = - idx === 0 - ? getFeatureTier(team) === 'starter' - ? AIExplainer.STARTER - : AIExplainer.PREMIUM_REFLECTIONS - : undefined - const topicSummaryComment = createAIComment( - discussionId, - buildCommentContentBlock('🤖 Topic Summary', group.summary, topicSummaryExplainerText), - 0 - ) - comments.push(topicSummaryComment) - } if (group.discussionPromptQuestion) { const topicSummaryComment = createAIComment( discussionId, diff --git a/packages/server/graphql/mutations/helpers/handleCompletedStage.ts b/packages/server/graphql/mutations/helpers/handleCompletedStage.ts index 785568a6396..e5be795830a 100644 --- a/packages/server/graphql/mutations/helpers/handleCompletedStage.ts +++ b/packages/server/graphql/mutations/helpers/handleCompletedStage.ts @@ -112,7 +112,7 @@ const handleCompletedRetrospectiveStage = async ( })) await Promise.all([ insertDiscussions(discussions), - addAIGeneratedContentToThreads(discussPhaseStages, meetingId, teamId, dataLoader), + addAIGeneratedContentToThreads(discussPhaseStages, meetingId, dataLoader), publishToEmbedder({jobType: 'relatedDiscussions:start', data: {meetingId}, priority: 0}) ]) if (videoMeetingURL) { From 39e6545b1589c99326250d0f199c1ece75a21a7d Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Fri, 3 May 2024 12:35:15 +0100 Subject: [PATCH 2/6] remove discussion prompt from summary --- .../MeetingSummaryEmail/RetroTopic.tsx | 31 +++++-------------- packages/server/graphql/types/Discussion.ts | 2 +- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/RetroTopic.tsx b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/RetroTopic.tsx index d89d5c32738..b5b46325d23 100644 --- a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/RetroTopic.tsx +++ b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/RetroTopic.tsx @@ -90,7 +90,6 @@ const RetroTopic = (props: Props) => { reflections { ...EmailReflectionCard_reflection } - discussionPromptQuestion } discussion { commentCount @@ -121,7 +120,7 @@ const RetroTopic = (props: Props) => { const {reflectionGroup, discussion, id: stageId} = stage const {commentCount, discussionSummary} = discussion - const {reflections, title, voteCount, discussionPromptQuestion} = reflectionGroup! + const {reflections, title, voteCount} = reflectionGroup! const imageSource = isEmail ? 'static' : 'local' const icon = imageSource === 'local' ? 'thumb_up_18.svg' : 'thumb_up_18@3x.png' const src = `${ExternalLinks.EMAIL_CDN}${icon}` @@ -143,29 +142,15 @@ const RetroTopic = (props: Props) => { - {(discussionPromptQuestion || discussionSummary) && ( + {discussionSummary && ( - {discussionPromptQuestion && ( - <> - - {'🤖 Discussion Question'} - - - {discussionPromptQuestion} - - - )} - {discussionSummary && ( - <> - - {'🤖 Discussion Summary'} - - - {discussionSummary} - - - )} + + {'🤖 Discussion Summary'} + + + {discussionSummary} + )} diff --git a/packages/server/graphql/types/Discussion.ts b/packages/server/graphql/types/Discussion.ts index 556401ba1cc..cdc01159736 100644 --- a/packages/server/graphql/types/Discussion.ts +++ b/packages/server/graphql/types/Discussion.ts @@ -155,7 +155,7 @@ const Discussion = new GraphQLObjectType({ }, summary: { type: GraphQLString, - description: `The GPT-3 generated summary of the discussion. Undefined if the user doesnt have access to the feature or the stage isn't completed` + description: `The AI generated summary of the discussion. Undefined if the user doesnt have access to the feature or the stage isn't completed` } }) }) From 16f2ed3f1a678c7d436c28a1de10b94c8d99c826 Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Fri, 3 May 2024 12:41:18 +0100 Subject: [PATCH 3/6] refactor generate group summaries to generate discussion prompt --- ...mmaries.ts => generateDiscussionPrompt.ts} | 23 ++++++------------- .../mutations/helpers/handleCompletedStage.ts | 4 ++-- .../graphql/types/RetroReflectionGroup.ts | 4 ---- 3 files changed, 9 insertions(+), 22 deletions(-) rename packages/server/graphql/mutations/helpers/{generateGroupSummaries.ts => generateDiscussionPrompt.ts} (72%) diff --git a/packages/server/graphql/mutations/helpers/generateGroupSummaries.ts b/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts similarity index 72% rename from packages/server/graphql/mutations/helpers/generateGroupSummaries.ts rename to packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts index 3a827ca20d1..0bf728b2dfa 100644 --- a/packages/server/graphql/mutations/helpers/generateGroupSummaries.ts +++ b/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts @@ -5,7 +5,7 @@ import sendToSentry from '../../../utils/sendToSentry' import {DataLoaderWorker} from '../../graphql' import canAccessAISummary from './canAccessAISummary' -const generateGroupSummaries = async ( +const generateDiscussionPrompt = async ( meetingId: string, teamId: string, dataLoader: DataLoaderWorker, @@ -30,7 +30,7 @@ const generateGroupSummaries = async ( const pg = getKysely() const manager = new OpenAIServerManager() if (!reflectionGroups.length) { - const error = new Error('No reflection groups in generateGroupSummaries') + const error = new Error('No reflection groups in generateDiscussionPrompt') sendToSentry(error, {userId: facilitator.id, tags: {meetingId}}) return } @@ -40,30 +40,21 @@ const generateGroupSummaries = async ( ({reflectionGroupId}) => reflectionGroupId === group.id ) if (reflectionsByGroupId.length <= 1) return - const reflectionTextByGroupId = reflectionsByGroupId.map( - ({plaintextContent}) => plaintextContent - ) - const [fullSummary, fullQuestion] = await Promise.all([ - manager.getSummary(reflectionTextByGroupId), + const [fullQuestion] = await Promise.all([ manager.getDiscussionPromptQuestion(group.title ?? 'Unknown', reflectionsByGroupId) ]) - if (!fullSummary && !fullQuestion) return - const summary = fullSummary?.slice(0, 2000) + if (!fullQuestion) return const discussionPromptQuestion = fullQuestion?.slice(0, 2000) return Promise.all([ pg .updateTable('RetroReflectionGroup') - .set({summary, discussionPromptQuestion}) + .set({discussionPromptQuestion}) .where('id', '=', group.id) .execute(), - r - .table('RetroReflectionGroup') - .get(group.id) - .update({summary, discussionPromptQuestion}) - .run() + r.table('RetroReflectionGroup').get(group.id).update({discussionPromptQuestion}).run() ]) }) ) } -export default generateGroupSummaries +export default generateDiscussionPrompt diff --git a/packages/server/graphql/mutations/helpers/handleCompletedStage.ts b/packages/server/graphql/mutations/helpers/handleCompletedStage.ts index e5be795830a..8227ec6fe69 100644 --- a/packages/server/graphql/mutations/helpers/handleCompletedStage.ts +++ b/packages/server/graphql/mutations/helpers/handleCompletedStage.ts @@ -13,8 +13,8 @@ import {DataLoaderWorker} from '../../graphql' import addAIGeneratedContentToThreads from './addAIGeneratedContentToThreads' import addDiscussionTopics from './addDiscussionTopics' import addRecallBot from './addRecallBot' +import generateDiscussionPrompt from './generateDiscussionPrompt' import generateDiscussionSummary from './generateDiscussionSummary' -import generateGroupSummaries from './generateGroupSummaries' import generateGroups from './generateGroups' import {publishToEmbedder} from './publishToEmbedder' import removeEmptyReflections from './removeEmptyReflections' @@ -92,7 +92,7 @@ const handleCompletedRetrospectiveStage = async ( .run() data.meeting = meeting // dont await for the OpenAI API response - generateGroupSummaries(meeting.id, teamId, dataLoader, facilitatorUserId) + generateDiscussionPrompt(meeting.id, teamId, dataLoader, facilitatorUserId) } return {[stage.phaseType]: data} diff --git a/packages/server/graphql/types/RetroReflectionGroup.ts b/packages/server/graphql/types/RetroReflectionGroup.ts index 87dca57750f..7fb07754d0c 100644 --- a/packages/server/graphql/types/RetroReflectionGroup.ts +++ b/packages/server/graphql/types/RetroReflectionGroup.ts @@ -87,10 +87,6 @@ const RetroReflectionGroup: GraphQLObjectType = new GraphQLObjectType Date: Fri, 3 May 2024 15:33:42 +0100 Subject: [PATCH 4/6] show loading in summary if there is more than one reflection --- .../WholeMeetingSummary.tsx | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx index 5bc27573613..64ab46e6c13 100644 --- a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx +++ b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx @@ -26,16 +26,8 @@ const WholeMeetingSummary = (props: Props) => { } ... on RetrospectiveMeeting { reflectionGroups(sortBy: voteCount) { - summary - } - phases { - phaseType - ... on DiscussPhase { - stages { - discussion { - summary - } - } + reflections { + id } } } @@ -49,14 +41,12 @@ const WholeMeetingSummary = (props: Props) => { meetingRef ) if (meeting.__typename === 'RetrospectiveMeeting') { - const {summary: wholeMeetingSummary, reflectionGroups, phases} = meeting - const discussPhase = phases!.find((phase) => phase.phaseType === 'discuss') - const {stages} = discussPhase ?? {} - const hasTopicSummary = reflectionGroups!.some((group) => group.summary) - const hasDiscussionSummary = !!stages?.some((stage) => stage.discussion?.summary) - const hasOpenAISummary = hasTopicSummary || hasDiscussionSummary - if (!hasOpenAISummary) return null - if (hasOpenAISummary && !wholeMeetingSummary) return + const {summary: wholeMeetingSummary, reflectionGroups, organization} = meeting + const hasMoreThanOneReflection = + (reflectionGroups?.length && reflectionGroups.length > 1) || + reflectionGroups?.some((group) => group.reflections.length > 1) + if (!hasMoreThanOneReflection || organization.featureFlags.noAISummary) return null + if (!wholeMeetingSummary) return return } else if (meeting.__typename === 'TeamPromptMeeting') { const {summary: wholeMeetingSummary, responses, organization} = meeting From f213bc69529bf5c23bcf63abce6264db2ab1a4d9 Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Tue, 7 May 2024 10:14:57 +0100 Subject: [PATCH 5/6] remove summary query from endRetro mutation --- .../WholeMeetingSummary.tsx | 5 ++-- .../mutations/EndRetrospectiveMutation.ts | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx index 64ab46e6c13..820491bffde 100644 --- a/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx +++ b/packages/client/modules/email/components/SummaryEmail/MeetingSummaryEmail/WholeMeetingSummary.tsx @@ -42,9 +42,8 @@ const WholeMeetingSummary = (props: Props) => { ) if (meeting.__typename === 'RetrospectiveMeeting') { const {summary: wholeMeetingSummary, reflectionGroups, organization} = meeting - const hasMoreThanOneReflection = - (reflectionGroups?.length && reflectionGroups.length > 1) || - reflectionGroups?.some((group) => group.reflections.length > 1) + const reflections = reflectionGroups?.flatMap((group) => group.reflections) // reflectionCount hasn't been calculated yet so check reflections length + const hasMoreThanOneReflection = reflections?.length && reflections.length > 1 if (!hasMoreThanOneReflection || organization.featureFlags.noAISummary) return null if (!wholeMeetingSummary) return return diff --git a/packages/client/mutations/EndRetrospectiveMutation.ts b/packages/client/mutations/EndRetrospectiveMutation.ts index 5d27418cdd1..4c339e8541a 100644 --- a/packages/client/mutations/EndRetrospectiveMutation.ts +++ b/packages/client/mutations/EndRetrospectiveMutation.ts @@ -31,8 +31,12 @@ graphql` autogroupReflectionGroups { groupTitle } + organization { + featureFlags { + noAISummary + } + } reflectionGroups(sortBy: voteCount) { - summary reflections { id } @@ -43,13 +47,6 @@ graphql` } phases { phaseType - ... on DiscussPhase { - stages { - discussion { - summary - } - } - } } } team { @@ -109,7 +106,14 @@ export const endRetrospectiveTeamOnNext: OnNextHandler< const {isKill, meeting} = payload const {atmosphere, history} = context if (!meeting) return - const {id: meetingId, teamId, reflectionGroups, phases, autogroupReflectionGroups} = meeting + const { + id: meetingId, + teamId, + reflectionGroups, + phases, + autogroupReflectionGroups, + organization + } = meeting if (meetingId === RetroDemo.MEETING_ID) { if (isKill) { window.localStorage.removeItem('retroDemo') @@ -122,12 +126,9 @@ export const endRetrospectiveTeamOnNext: OnNextHandler< history.push(`/team/${teamId}`) popEndMeetingToast(atmosphere, meetingId) } else { - const discussPhase = phases.find((phase) => phase.phaseType === 'discuss') - const {stages} = discussPhase ?? {} - const hasTopicSummary = reflectionGroups.some((group) => group.summary) const reflections = reflectionGroups.flatMap((group) => group.reflections) // reflectionCount hasn't been calculated yet so check reflections length - const hasDiscussionSummary = !!stages?.some((stage) => stage.discussion?.summary) - const hasOpenAISummary = hasTopicSummary || hasDiscussionSummary + const hasMoreThanOneReflection = reflections.length > 1 + const hasOpenAISummary = hasMoreThanOneReflection || !organization.featureFlags.noAISummary const hasTeamHealth = phases.some((phase) => phase.phaseType === 'TEAM_HEALTH') const pathname = `/new-summary/${meetingId}` const search = new URLSearchParams() From 4ee622884b4c504c73d6fc2175ca46d598a2201f Mon Sep 17 00:00:00 2001 From: Nick O'Ferrall Date: Tue, 7 May 2024 15:26:26 +0100 Subject: [PATCH 6/6] remove promise all --- packages/client/mutations/EndRetrospectiveMutation.ts | 2 +- .../graphql/mutations/helpers/generateDiscussionPrompt.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/client/mutations/EndRetrospectiveMutation.ts b/packages/client/mutations/EndRetrospectiveMutation.ts index 4c339e8541a..f087fbe1197 100644 --- a/packages/client/mutations/EndRetrospectiveMutation.ts +++ b/packages/client/mutations/EndRetrospectiveMutation.ts @@ -128,7 +128,7 @@ export const endRetrospectiveTeamOnNext: OnNextHandler< } else { const reflections = reflectionGroups.flatMap((group) => group.reflections) // reflectionCount hasn't been calculated yet so check reflections length const hasMoreThanOneReflection = reflections.length > 1 - const hasOpenAISummary = hasMoreThanOneReflection || !organization.featureFlags.noAISummary + const hasOpenAISummary = hasMoreThanOneReflection && !organization.featureFlags.noAISummary const hasTeamHealth = phases.some((phase) => phase.phaseType === 'TEAM_HEALTH') const pathname = `/new-summary/${meetingId}` const search = new URLSearchParams() diff --git a/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts b/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts index 0bf728b2dfa..bb7a245ca2f 100644 --- a/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts +++ b/packages/server/graphql/mutations/helpers/generateDiscussionPrompt.ts @@ -40,9 +40,10 @@ const generateDiscussionPrompt = async ( ({reflectionGroupId}) => reflectionGroupId === group.id ) if (reflectionsByGroupId.length <= 1) return - const [fullQuestion] = await Promise.all([ - manager.getDiscussionPromptQuestion(group.title ?? 'Unknown', reflectionsByGroupId) - ]) + const fullQuestion = await manager.getDiscussionPromptQuestion( + group.title ?? 'Unknown', + reflectionsByGroupId + ) if (!fullQuestion) return const discussionPromptQuestion = fullQuestion?.slice(0, 2000) return Promise.all([