Skip to content

Commit 83dcf2d

Browse files
authored
feat: results view and SFERA and GI ratings(#167)
preparation for SFERA and GI experiments build: use SENTRY_ENV to control sentry config feat: ratings global issue feat: show summary of ratings for responses GI feat: implement SFERA rating fix: hook automatic response generation on next steps refactor: split prompts and main translations fix: missing assistant id when generating responses with chatbot fix(langs): es translations fix: show correct value for activity switch in settings
1 parent cfeb0bb commit 83dcf2d

35 files changed

+1973
-617
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@mui/lab": "5.0.0-alpha.169",
3737
"@mui/material": "5.15.14",
3838
"@mui/x-data-grid": "^6.19.4",
39+
"@nivo/boxplot": "^0.85.1",
3940
"@sentry/react": "7.107.0",
4041
"@tanstack/react-query": "^4.36.1",
4142
"@tanstack/react-query-devtools": "^4.36.1",

src/config/i18n.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@ import { initReactI18next } from 'react-i18next';
22

33
import i18n from 'i18next';
44

5-
import en from '../langs/en/main.json';
6-
import fr from '../langs/fr/main.json';
7-
import { DEFAULT_LANG } from './constants';
5+
import mainEn from '../langs/en/main.json';
6+
import promptsEn from '../langs/en/prompts.json';
7+
8+
import mainFr from '../langs/fr/main.json';
9+
import promptsFr from '../langs/fr/prompts.json';
810

9-
export const defaultNS = 'translations';
10-
export const resources = {
11-
en,
12-
fr,
13-
} as const;
11+
import mainEs from '../langs/es/main.json';
12+
import promptsEs from '../langs/es/prompts.json';
1413

15-
declare module 'react-i18next' {
16-
interface CustomTypeOptions {
17-
defaultNS: typeof defaultNS;
18-
resources: (typeof resources)['en'];
19-
}
20-
}
14+
import { DEFAULT_LANG } from './constants';
15+
16+
export const TRANSLATIONS_NS = 'translations';
17+
export const PROMPTS_NS = 'prompts';
18+
export const defaultNS = TRANSLATIONS_NS;
2119

2220
i18n.use(initReactI18next).init({
23-
resources,
2421
lng: DEFAULT_LANG,
2522
// debug only when not in production
2623
debug: import.meta.env.DEV,
@@ -34,4 +31,11 @@ i18n.use(initReactI18next).init({
3431
fallbackLng: 'en',
3532
});
3633

34+
i18n.addResourceBundle('en', TRANSLATIONS_NS, mainEn);
35+
i18n.addResourceBundle('en', PROMPTS_NS, promptsEn);
36+
i18n.addResourceBundle('fr', TRANSLATIONS_NS, mainFr);
37+
i18n.addResourceBundle('fr', PROMPTS_NS, promptsFr);
38+
i18n.addResourceBundle('es', TRANSLATIONS_NS, mainEs);
39+
i18n.addResourceBundle('es', PROMPTS_NS, promptsEs);
40+
3741
export default i18n;

src/config/prompts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ export const getSingleResponsePrompt = (prompt: string): string =>
1212

1313
export const promptForSingleResponse = (
1414
problemStatement: string,
15-
t: TFunction,
15+
t: TFunction<'prompts', undefined>,
1616
): string =>
17-
t('PROMPTS.SINGLE_RESPONSE', {
17+
t('SINGLE_RESPONSE', {
1818
problemStatement,
1919
maxChars: RESPONSE_MAXIMUM_LENGTH,
2020
});
2121

2222
export const promptForSingleResponseAndProvideResponses = (
2323
problemStatement: string,
2424
responses: string[],
25-
t: TFunction,
25+
t: TFunction<'prompts', undefined>,
2626
): string => {
2727
const responsesString = responses.map(
2828
(r) => `<solution>\n${r}\n</solution>\n`,
2929
);
30-
return t('PROMPTS.SINGLE_RESPONSE_AND_PROVIDE_RESPONSES', {
30+
return t('SINGLE_RESPONSE_AND_PROVIDE_RESPONSES', {
3131
problemStatement,
3232
responses: responsesString,
3333
maxChars: RESPONSE_MAXIMUM_LENGTH,

src/config/selectors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ export const NEXT_STEP_BTN_CY = 'next-step-btn';
3434

3535
export const buildDataCy = (selector: string): string =>
3636
`[data-cy=${selector}]`;
37+
38+
export const RESULTS_VIEW_CY = 'results-view';

src/config/sentry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type SentryConfigType = {
1010
};
1111

1212
export const generateSentryConfig = (): SentryConfigType => {
13-
let SENTRY_ENVIRONMENT = 'development';
13+
let SENTRY_ENVIRONMENT = SENTRY_ENV || 'development';
1414
let SENTRY_TRACE_SAMPLE_RATE = 1.0;
1515
// This sets the sample rate to be 10%. You may want this to be 100% while
1616
// in development and sample at a lower rate in production

src/hooks/useAssistants.ts

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import { ChatbotRole } from '@graasp/sdk';
22

3-
import { ChatbotResponseAppData } from '@/config/appDataTypes';
3+
import { ChatbotResponseAppData, ResponseAppData } from '@/config/appDataTypes';
44
import {
55
DEFAULT_CHATBOT_RESPONSE_APP_DATA,
66
RESPONSE_MAXIMUM_LENGTH,
77
} from '@/config/constants';
8-
import { getSingleResponsePrompt } from '@/config/prompts';
8+
import {
9+
getSingleResponsePrompt,
10+
promptForSingleResponse,
11+
promptForSingleResponseAndProvideResponses,
12+
} from '@/config/prompts';
913
import { mutations } from '@/config/queryClient';
1014
import { AssistantPersona } from '@/interfaces/assistant';
1115
import { useAppDataContext } from '@/modules/context/AppDataContext';
1216
import { useSettings } from '@/modules/context/SettingsContext';
1317
import { useTranslation } from 'react-i18next';
18+
import { useActivityContext } from '@/modules/context/ActivityContext';
1419

1520
interface UseAssistantsValues {
1621
generateSingleResponse: () => Promise<ChatbotResponseAppData | undefined>;
@@ -24,13 +29,25 @@ interface UseAssistantsValues {
2429
reformulateResponse: (
2530
response: string,
2631
) => Promise<ChatbotResponseAppData | undefined>;
32+
generateResponsesWithEachAssistant: () => Promise<
33+
Promise<ResponseAppData | undefined>[]
34+
>;
2735
}
2836

2937
const useAssistants = (): UseAssistantsValues => {
30-
const { t } = useTranslation('translations', { keyPrefix: 'PROMPTS' });
38+
const { t } = useTranslation('prompts');
3139
const { mutateAsync: postChatBot } = mutations.usePostChatBot();
32-
const { chatbot, instructions: generalPrompt, assistants } = useSettings();
40+
const {
41+
chatbot,
42+
instructions: generalPrompt,
43+
assistants,
44+
instructions,
45+
} = useSettings();
3346
const { postAppDataAsync } = useAppDataContext();
47+
48+
const { assistantsResponsesSets, round, allResponses, postResponse } =
49+
useActivityContext();
50+
3451
const reformulateResponse = (
3552
response: string,
3653
): Promise<ChatbotResponseAppData | undefined> =>
@@ -86,7 +103,9 @@ const useAssistants = (): UseAssistantsValues => {
86103
]).then((ans) => {
87104
const a = postAppDataAsync({
88105
...DEFAULT_CHATBOT_RESPONSE_APP_DATA,
89-
data: ans,
106+
data: {
107+
...ans,
108+
},
90109
}) as Promise<ChatbotResponseAppData>;
91110
return a;
92111
});
@@ -104,7 +123,10 @@ const useAssistants = (): UseAssistantsValues => {
104123
]).then((ans) => {
105124
const a = postAppDataAsync({
106125
...DEFAULT_CHATBOT_RESPONSE_APP_DATA,
107-
data: ans,
126+
data: {
127+
ans,
128+
assistantId: assistant.id,
129+
},
108130
}) as Promise<ChatbotResponseAppData>;
109131
return a;
110132
});
@@ -114,11 +136,58 @@ const useAssistants = (): UseAssistantsValues => {
114136
): Promise<Promise<ChatbotResponseAppData | undefined>[]> =>
115137
assistants.assistants.map((p) => promptAssistant(p, prompt));
116138

139+
const generateResponsesWithEachAssistant = async (): Promise<
140+
Promise<ResponseAppData | undefined>[]
141+
> => {
142+
const responsesAssistants = assistants.assistants
143+
.map((persona) => {
144+
const assistantSet = assistantsResponsesSets.find(
145+
(set) =>
146+
set.data.assistant === persona.id && set.data.round === round - 1,
147+
);
148+
if (assistantSet) {
149+
const responses = assistantSet.data.responses.map(
150+
(r) => allResponses.find(({ id }) => r === id)?.data.response || '',
151+
);
152+
return promptAssistant(
153+
persona,
154+
promptForSingleResponseAndProvideResponses(
155+
instructions.title.content,
156+
responses,
157+
t,
158+
),
159+
);
160+
}
161+
return promptAssistant(
162+
persona,
163+
promptForSingleResponse(instructions.title.content, t),
164+
);
165+
})
166+
.map((promise) =>
167+
promise.then((assistantResponseAppData) => {
168+
if (assistantResponseAppData) {
169+
const { completion: response, assistantId } =
170+
assistantResponseAppData.data;
171+
return postResponse({
172+
response,
173+
round,
174+
bot: true,
175+
assistantId,
176+
});
177+
}
178+
return assistantResponseAppData;
179+
}),
180+
);
181+
182+
return responsesAssistants;
183+
};
184+
117185
return {
118186
generateSingleResponse,
119187
promptAssistant,
120188
promptAllAssistants,
121189
reformulateResponse,
190+
generateResponsesWithEachAssistant,
122191
};
123192
};
124193

src/hooks/useRatings.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { AppDataTypes, RatingsAppData } from '@/config/appDataTypes';
2+
import { EvaluationType } from '@/interfaces/evaluationType';
3+
import {
4+
DimensionsOfGIRatings,
5+
SFERARating,
6+
UsefulnessNoveltyRatings,
7+
} from '@/interfaces/ratings';
8+
import { useAppDataContext } from '@/modules/context/AppDataContext';
9+
import { useCallback, useMemo } from 'react';
10+
11+
interface UseRatingsValue<T> {
12+
allRatings: RatingsAppData<T>[];
13+
getRatingsForResponse: (id: string) => RatingsAppData<T>[];
14+
}
15+
16+
type ReturnRating<T> = T extends EvaluationType.DimensionsOfGIRating
17+
? DimensionsOfGIRatings
18+
: T extends EvaluationType.UsefulnessNoveltyRating
19+
? UsefulnessNoveltyRatings
20+
: T extends EvaluationType.SFERARating
21+
? SFERARating
22+
: null;
23+
24+
const useRatings = (
25+
evaluationType: EvaluationType,
26+
): UseRatingsValue<ReturnRating<typeof evaluationType>> => {
27+
type R = ReturnRating<typeof evaluationType>;
28+
const { appData } = useAppDataContext();
29+
const allRatings = useMemo(
30+
() =>
31+
appData.filter(
32+
({ type, data }) =>
33+
type === AppDataTypes.Ratings && data?.type === evaluationType,
34+
) as RatingsAppData<R>[],
35+
[appData, evaluationType],
36+
);
37+
38+
const getRatingsForResponse = useCallback(
39+
(id: string) => allRatings.filter(({ data }) => data?.ideaRef === id),
40+
[allRatings],
41+
);
42+
43+
return { allRatings, getRatingsForResponse };
44+
};
45+
46+
export default useRatings;

src/hooks/useSteps.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useActivityContext } from '@/modules/context/ActivityContext';
33
import { useSettings } from '@/modules/context/SettingsContext';
44
import { useMemo } from 'react';
55
import useActions from './useActions';
6+
import useAssistants from './useAssistants';
67

78
interface UseStepsValues {
89
changeStep: (newStep: ActivityStep, index: number) => void;
@@ -24,6 +25,8 @@ const useSteps = (): UseStepsValues => {
2425
deleteResponsesSetsForRound,
2526
} = useActivityContext();
2627

28+
const { generateResponsesWithEachAssistant } = useAssistants();
29+
2730
const { postNextStepAction, postPreviousStepAction } = useActions();
2831
const { activity } = useSettings();
2932
const { steps } = activity;
@@ -75,9 +78,12 @@ const useSteps = (): UseStepsValues => {
7578
const nextStepIndex = (stepIndex ?? 0) + 1;
7679

7780
if ((nextStep?.round || 0) > round) {
78-
await createAllResponsesSet().then(() => {
79-
changeStep(nextStep, nextStepIndex);
80-
});
81+
// TODO: Insane amount of work here. REFACTOR!
82+
await generateResponsesWithEachAssistant().then(() =>
83+
createAllResponsesSet().then(() => {
84+
changeStep(nextStep, nextStepIndex);
85+
}),
86+
);
8187
} else {
8288
changeStep(nextStep, nextStepIndex);
8389
}

src/interfaces/chatbot.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
import { ChatBotCompletion } from '@graasp/apps-query-client';
2+
import { AssistantId } from './assistant';
23

3-
export type ChatbotResponseData = ChatBotCompletion;
4+
export type ChatbotResponseData = ChatBotCompletion & {
5+
assistantId?: AssistantId;
6+
};

src/interfaces/evaluationType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export enum EvaluationType {
22
UsefulnessNoveltyRating = 'usefulness-novelty-rating',
3+
DimensionsOfGIRating = 'dimensions-gi-rating',
4+
SFERARating = 'sfera-rating',
35
Vote = 'vote',
46
None = 'none',
57
}

0 commit comments

Comments
 (0)