diff --git a/codegen.json b/codegen.json index cb824aae51a..a24a1e5abf1 100644 --- a/codegen.json +++ b/codegen.json @@ -90,7 +90,6 @@ "GenerateGroupsSuccess": "./types/GenerateGroupsSuccess#GenerateGroupsSuccessSource", "GenerateInsightSuccess": "./types/GenerateInsightSuccess#GenerateInsightSuccessSource", "GenerateRetroSummariesSuccess": "./types/GenerateRetroSummariesSuccess#GenerateRetroSummariesSuccessSource", - "GetTemplateSuggestionSuccess": "./types/GetTemplateSuggestionSuccess#GetTemplateSuggestionSuccessSource", "GitHubIntegration": "../../postgres/queries/getGitHubAuthByUserIdTeamId#GitHubAuth", "GitLabIntegration": "./types/GitLabIntegration#GitLabIntegrationSource", "IntegrationProviderOAuth1": "../../postgres/queries/getIntegrationProvidersByIds#TIntegrationProvider", diff --git a/package.json b/package.json index 186a2971fd3..9dcba23f24f 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,7 @@ "git-url-parse": "12.0.0", "fbjs": "^3.0.0", "parse-url": "^8.1.0", - "recursive-readdir": "^2.2.3", - "json5": "^2.2.3" + "recursive-readdir": "^2.2.3" }, "devDependencies": { "@babel/core": "^7.20.12", diff --git a/packages/client/components/ActivityLibrary/AISearch.tsx b/packages/client/components/ActivityLibrary/AISearch.tsx deleted file mode 100644 index 4bb9f9e7cc7..00000000000 --- a/packages/client/components/ActivityLibrary/AISearch.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import * as React from 'react' -import {useState} from 'react' -import {GetTemplateSuggestionMutation$data} from '../../__generated__/GetTemplateSuggestionMutation.graphql' -import useAtmosphere from '../../hooks/useAtmosphere' -import useMutationProps from '../../hooks/useMutationProps' -import GetTemplateSuggestionMutation from '../../mutations/GetTemplateSuggestionMutation' -import LoadingComponent from '../LoadingComponent/LoadingComponent' -import StyledError from '../StyledError' -import ActivityGrid from './ActivityGrid' - -type SuggestedTemplate = - GetTemplateSuggestionMutation$data['getTemplateSuggestion']['suggestedTemplate'] - -const AISearch = () => { - const atmosphere = useAtmosphere() - const {onCompleted, onError, submitMutation, submitting, error} = useMutationProps() - const [suggestedTemplate, setSuggestedTemplate] = useState(null) - const [explanation, setExplanation] = useState('') - const [prompt, setPrompt] = useState('') - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault() - if (!prompt) { - const error = new Error('Please enter a prompt') - onError(error) - return - } - const variables = {prompt} - submitMutation() - GetTemplateSuggestionMutation(atmosphere, variables, { - onError, - onCompleted: (res: GetTemplateSuggestionMutation$data) => { - const {getTemplateSuggestion} = res - if (getTemplateSuggestion?.error) { - const error = new Error(res.getTemplateSuggestion?.error?.message) - onError(error) - } else if (getTemplateSuggestion.explanation && getTemplateSuggestion.suggestedTemplate) { - setSuggestedTemplate(getTemplateSuggestion.suggestedTemplate) - setExplanation(getTemplateSuggestion.explanation) - onCompleted() - } - } - }) - } - - const handlePromptChange = (e: React.ChangeEvent) => { - setPrompt(e.target.value) - } - - return ( - <> -
- - -
-
- {submitting && } - {error?.message && !submitting && ( - {`Despite its best efforts, our AI couldn't find a matching template. Try again?`} - )} - {!submitting && suggestedTemplate && ( - <> -
Our AI's Suggestion
-
-
{explanation}
-
-
- -
- - )} -
- - ) -} - -export default AISearch diff --git a/packages/client/components/ActivityLibrary/ActivityLibrary.tsx b/packages/client/components/ActivityLibrary/ActivityLibrary.tsx index 4c9114c897b..da2547456e0 100644 --- a/packages/client/components/ActivityLibrary/ActivityLibrary.tsx +++ b/packages/client/components/ActivityLibrary/ActivityLibrary.tsx @@ -24,7 +24,6 @@ import logoMarkPurple from '../../styles/theme/images/brand/mark-color.svg' import SendClientSideEvent from '../../utils/SendClientSideEvent' import IconLabel from '../IconLabel' import LoadingComponent from '../LoadingComponent/LoadingComponent' -import AISearch from './AISearch' import ActivityGrid from './ActivityGrid' import ActivityLibraryEmptyState from './ActivityLibraryEmptyState' import { @@ -117,9 +116,6 @@ const query = graphql` } } } - organizations { - hasAITemplateFlag: featureFlag(featureName: "aiTemplate") - } } } ` @@ -226,8 +222,7 @@ export const ActivityLibrary = (props: Props) => { const {queryRef} = props const data = usePreloadedQuery(query, queryRef) const {viewer} = data - const {availableTemplates, organizations} = viewer - const hasAITemplateFeatureFlag = organizations.some((org) => org.hasAITemplateFlag) + const {availableTemplates} = viewer const [isSearching, setIsSearching] = useState(true) const [templateSearch, refetchTemplateSearch] = useRefetchableFragment< @@ -361,17 +356,16 @@ export const ActivityLibrary = (props: Props) => { Start Activity - {!hasAITemplateFeatureFlag && ( -
- { - onQueryChange(e) - setSearch(e.target.value) - }} - /> -
- )} +
+ { + onQueryChange(e) + setSearch(e.target.value) + }} + /> +
+ { - {hasAITemplateFeatureFlag && ( -
- -
- )} {templatesToRender.length === 0 && !showLoading ? ( = ( - atmosphere, - variables, - {onError, onCompleted} -) => { - return commitMutation(atmosphere, { - mutation, - variables, - onCompleted, - onError - }) -} - -export default GetTemplateSuggestionMutation diff --git a/packages/server/graphql/public/mutations/getTemplateSuggestion.ts b/packages/server/graphql/public/mutations/getTemplateSuggestion.ts deleted file mode 100644 index 0e2267bcf13..00000000000 --- a/packages/server/graphql/public/mutations/getTemplateSuggestion.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {getUserId} from '../../../utils/authorization' -import OpenAIServerManager from '../../../utils/OpenAIServerManager' -import standardError from '../../../utils/standardError' -import isValid from '../../isValid' -import {MutationResolvers} from '../resolverTypes' - -type Prompt = { - question: string - description: string -} - -type PromptsByTemplate = { - [templateId: string]: Prompt[] -} - -const getTemplateSuggestion: MutationResolvers['getTemplateSuggestion'] = async ( - _source, - {prompt}, - {authToken, dataLoader} -) => { - const viewerId = getUserId(authToken) - const organizationUsers = await dataLoader.get('organizationUsersByUserId').load(viewerId) - const userOrgIds = organizationUsers.map(({orgId}) => orgId) - const availableOrgIds = ['aGhostOrg', ...userOrgIds] - const allTemplates = (await dataLoader.get('meetingTemplatesByOrgId').loadMany(availableOrgIds)) - .filter(isValid) - .flat() - - const templateIds = allTemplates.map((template) => template.id) - const prompts = (await dataLoader.get('reflectPromptsByTemplateId').loadMany(templateIds)) - .filter(isValid) - .flat() - - const promptsByTemplate: PromptsByTemplate = {} - prompts.forEach((prompt) => { - const {templateId} = prompt - if (!promptsByTemplate[templateId]) { - promptsByTemplate[templateId] = [] - } - promptsByTemplate[templateId]!.push({ - question: prompt.question, - description: prompt.description - }) - }) - - const templatesWithPrompts = allTemplates.map((template) => ({ - templateId: template.id, - templateName: template.name, - prompts: promptsByTemplate[template.id] || [] - })) - - const manager = new OpenAIServerManager() - const templateRes = await manager.getTemplateSuggestion(templatesWithPrompts, prompt) - if (!templateRes) { - return standardError(new Error('Unable to get AI suggested template'), {userId: viewerId}) - } - - const data = { - suggestedTemplateId: templateRes.templateId, - explanation: templateRes.explanation - } - return data -} - -export default getTemplateSuggestion diff --git a/packages/server/graphql/public/typeDefs/GetTemplateSuggestionPayload.graphql b/packages/server/graphql/public/typeDefs/GetTemplateSuggestionPayload.graphql deleted file mode 100644 index 14ea93c2e95..00000000000 --- a/packages/server/graphql/public/typeDefs/GetTemplateSuggestionPayload.graphql +++ /dev/null @@ -1,4 +0,0 @@ -""" -Return value for getTemplateSuggestion, which could be an error -""" -union GetTemplateSuggestionPayload = ErrorPayload | GetTemplateSuggestionSuccess diff --git a/packages/server/graphql/public/typeDefs/GetTemplateSuggestionSuccess.graphql b/packages/server/graphql/public/typeDefs/GetTemplateSuggestionSuccess.graphql deleted file mode 100644 index ecb9431570f..00000000000 --- a/packages/server/graphql/public/typeDefs/GetTemplateSuggestionSuccess.graphql +++ /dev/null @@ -1,11 +0,0 @@ -type GetTemplateSuggestionSuccess { - """ - The template the AI suggested - """ - suggestedTemplate: MeetingTemplate! - - """ - The explanation from the AI - """ - explanation: String! -} diff --git a/packages/server/graphql/public/typeDefs/Mutation.graphql b/packages/server/graphql/public/typeDefs/Mutation.graphql index accf4fb30c3..48a23598d20 100644 --- a/packages/server/graphql/public/typeDefs/Mutation.graphql +++ b/packages/server/graphql/public/typeDefs/Mutation.graphql @@ -1460,16 +1460,6 @@ type Mutation { """ createStripeSubscription(orgId: ID!, paymentMethodId: ID!): CreateStripeSubscriptionPayload! - """ - Ask the AI for a template suggestion - """ - getTemplateSuggestion( - """ - The question the user has for the AI - """ - prompt: String! - ): GetTemplateSuggestionPayload! - """ Sign up or login using Google """ diff --git a/packages/server/graphql/public/types/GetTemplateSuggestionSuccess.ts b/packages/server/graphql/public/types/GetTemplateSuggestionSuccess.ts deleted file mode 100644 index 7ba81a50884..00000000000 --- a/packages/server/graphql/public/types/GetTemplateSuggestionSuccess.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {GetTemplateSuggestionSuccessResolvers} from '../resolverTypes' - -export type GetTemplateSuggestionSuccessSource = { - suggestedTemplateId: string - explanation: string -} - -const GetTemplateSuggestionSuccess: GetTemplateSuggestionSuccessResolvers = { - suggestedTemplate: async ({suggestedTemplateId}, _args, {dataLoader}) => { - const template = await dataLoader.get('meetingTemplates').loadNonNull(suggestedTemplateId) - return template - }, - explanation: ({explanation}) => explanation -} - -export default GetTemplateSuggestionSuccess diff --git a/packages/server/utils/OpenAIServerManager.ts b/packages/server/utils/OpenAIServerManager.ts index b73ad171339..6143be1775c 100644 --- a/packages/server/utils/OpenAIServerManager.ts +++ b/packages/server/utils/OpenAIServerManager.ts @@ -1,31 +1,14 @@ -import JSON5 from 'json5' import OpenAI from 'openai' import {ModifyType} from '../graphql/public/resolverTypes' import {RetroReflection} from '../postgres/types' import {Logger} from './Logger' import sendToSentry from './sendToSentry' -type Prompt = { - question: string - description: string -} - type InsightResponse = { wins: string[] challenges: string[] } -type Template = { - templateId: string - templateName: string - prompts: Prompt[] -} - -type AITemplateSuggestion = { - templateId: string - explanation: string -} - class OpenAIServerManager { private openAIApi constructor() { @@ -200,44 +183,6 @@ class OpenAIServerManager { } } - async getTemplateSuggestion(templates: Template[], userPrompt: string) { - if (!this.openAIApi) return null - const promptText = `Based on the user's input "${userPrompt}", identify the most suitable meeting template from the list below and provide a JSON response in the format: { templateId: "the chosen template ID", explanation: "reason for choosing this template" }. The explanation should be concise. Available templates are: ${templates - .map( - (template) => - `ID: ${template.templateId}, Name: ${template.templateName}, Prompts: ${template.prompts - .map((prompt) => `${prompt.question} - ${prompt.description}`) - .join('; ')}` - ) - .join('. ')}.` - - try { - const response = await this.openAIApi.chat.completions.create({ - model: 'gpt-4o-mini', - messages: [ - { - role: 'user', - content: promptText - } - ], - temperature: 0.7, - top_p: 1, - frequency_penalty: 0, - presence_penalty: 0 - }) - - const templateResponse = (response.choices[0]?.message?.content?.trim() as string) ?? null - const parsedResponse = JSON5.parse(templateResponse) - return parsedResponse as AITemplateSuggestion - } catch (e) { - const error = - e instanceof Error ? e : new Error('OpenAI failed to generate the suggested template') - Logger.error(error.message) - sendToSentry(error) - return null - } - } - async groupReflections(reflectionsText: string[], themes: string[]) { if (!this.openAIApi) return null diff --git a/yarn.lock b/yarn.lock index cc515886d1b..f4d90d92b47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15464,7 +15464,14 @@ json2csv@5.0.7: jsonparse "^1.3.1" lodash.get "^4.4.2" -json5@^1.0.1, json5@^2.1.2, json5@^2.2.0, json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: +json5@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.2.0, json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==