kpfadnis commited on
Commit
d23bbc5
·
1 Parent(s): 2d1bbfb

feat (RAG Task): Support for different context per evaluation. (#4)

Browse files
src/types.ts CHANGED
@@ -136,6 +136,8 @@ export interface Document {
136
  formattedText?: string;
137
  url?: string;
138
  title?: string;
 
 
139
  annotations?: DocumentAnnotation[];
140
  }
141
 
@@ -187,6 +189,7 @@ export interface TaskEvaluation {
187
  readonly annotations: {
188
  [key: string]: { [key: string]: Annotation };
189
  };
 
190
  [key: string]: any;
191
  }
192
 
 
136
  formattedText?: string;
137
  url?: string;
138
  title?: string;
139
+ score?: number;
140
+ query?: {};
141
  annotations?: DocumentAnnotation[];
142
  }
143
 
 
189
  readonly annotations: {
190
  [key: string]: { [key: string]: Annotation };
191
  };
192
+ readonly contexts?: Document[];
193
  [key: string]: any;
194
  }
195
 
src/views/task/RAGTask.tsx CHANGED
@@ -77,7 +77,8 @@ export default function RAGTask({
77
  updateCommentProvenance,
78
  }: Props) {
79
  // Step 1: Initialize state and necessary variables
80
- const [selectedModelIndex, setSelectedModelIndex] = useState<number>(0);
 
81
  const [showOverlap, setShowOverlap] = useState<boolean>(false);
82
  const [activeDocumentIndex, setActiveDocumentIndex] = useState<number>(0);
83
 
@@ -85,66 +86,75 @@ export default function RAGTask({
85
  // Step 2.a: Fetch data from data store
86
  const { item: data } = useDataStore();
87
 
88
- // Step 2.b: Fetch documents and evaluations for the current task
89
- const [documents, evaluations] = useMemo(() => {
90
- // Step 2.b.i: Fetch context documents
91
- const contextDocuments: Document[] = [];
92
- if (task?.contexts) {
93
- task.contexts.forEach((context, context_idx) => {
94
- if (data && data.documents) {
95
- const referenceDocument = data.documents.find(
96
- (document) => document.documentId === context.documentId,
97
- );
98
- if (referenceDocument) {
99
- // Step 2.b.i.*: Fetch context relevant annotations, if present
100
- if (
101
- task?.annotations &&
102
- task.annotations.hasOwnProperty('context_relevance')
103
- ) {
104
- const documentAnnotation: DocumentAnnotation = {
105
- text: 'Relevant',
106
- authors: [],
107
- color: 'green',
108
- };
109
- for (const [annotator, annotations] of Object.entries(
110
- task.annotations.context_relevance,
111
- )) {
112
- if (
113
- Array.isArray(annotations) &&
114
- annotations.includes(context_idx)
115
- ) {
116
- documentAnnotation.authors.push(annotator);
117
- }
118
- }
119
- if (!isEmpty(documentAnnotation.authors)) {
120
- referenceDocument.annotations = [documentAnnotation];
121
- }
122
- }
123
 
124
- contextDocuments.push(referenceDocument);
125
- } else {
126
- contextDocuments.push({
127
- documentId: context.documentId,
128
- text: 'Missing document text',
129
- });
130
- }
131
- } else {
132
- contextDocuments.push({
133
- documentId: context.documentId,
134
- text: 'Missing document text',
135
- });
136
- }
137
- });
138
- }
139
- // Step 2.b.ii: Fetch evaluations
140
  let taskEvaluations: TaskEvaluation[] | undefined = undefined;
141
  if (data) {
142
  taskEvaluations = data.evaluations.filter(
143
  (evaluation) => evaluation.taskId === task.taskId,
144
  );
145
 
146
- // Step: Compute context-response overlap and add to evaluation object
147
  taskEvaluations.forEach((evaluation) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  const textOverlaps: StringMatchObject[][] = [];
149
  contextDocuments.forEach((contextDocument) => {
150
  textOverlaps.push(
@@ -153,10 +163,13 @@ export default function RAGTask({
153
  });
154
 
155
  evaluation.overlaps = textOverlaps;
 
 
 
156
  });
157
  }
158
 
159
- return [contextDocuments, taskEvaluations];
160
  }, [task.taskId, task.contexts, data]);
161
 
162
  // Step 2.c: Build human & algorithmic metric maps
@@ -185,7 +198,7 @@ export default function RAGTask({
185
  metrics={metrics}
186
  task={task}
187
  evaluations={evaluations}
188
- documents={documents}
189
  onClose={() => {
190
  setTaskCopierModalOpen(false);
191
  }}
@@ -257,7 +270,7 @@ export default function RAGTask({
257
  </>
258
  ) : null}
259
  </div>
260
- {documents && (
261
  <div className={classes.contextContainer}>
262
  <div className={classes.header}>
263
  <h4>Contexts</h4>
@@ -290,13 +303,16 @@ export default function RAGTask({
290
  )}
291
  </div>
292
  <DocumentPanel
293
- documents={documents.map((document, documentIdx) => {
 
 
 
294
  return {
295
  documentId: document.documentId,
296
  text: showOverlap
297
  ? mark(
298
  document.text,
299
- evaluations[selectedModelIndex].overlaps[
300
  documentIdx
301
  ],
302
  'target',
@@ -326,7 +342,8 @@ export default function RAGTask({
326
  <div className={classes.evaluationsContainer}>
327
  <Tabs
328
  onChange={(e) => {
329
- setSelectedModelIndex(e.selectedIndex);
 
330
  }}
331
  >
332
  <TabList
@@ -345,7 +362,7 @@ export default function RAGTask({
345
  ))}
346
  </TabList>
347
  <TabPanels>
348
- {evaluations.map((evaluation) => (
349
  <TabPanel key={'model-' + evaluation.modelId + '-panel'}>
350
  <div className={classes.tabContainer}>
351
  <div className={classes.tabContentHeader}>
@@ -376,7 +393,8 @@ export default function RAGTask({
376
  >
377
  {parse(
378
  DOMPurify.sanitize(
379
- showOverlap
 
380
  ? mark(
381
  evaluation.modelResponse,
382
  evaluation.overlaps[activeDocumentIndex],
 
77
  updateCommentProvenance,
78
  }: Props) {
79
  // Step 1: Initialize state and necessary variables
80
+ const [selectedEvaluationIndex, setSelectedEvaluationIndex] =
81
+ useState<number>(0);
82
  const [showOverlap, setShowOverlap] = useState<boolean>(false);
83
  const [activeDocumentIndex, setActiveDocumentIndex] = useState<number>(0);
84
 
 
86
  // Step 2.a: Fetch data from data store
87
  const { item: data } = useDataStore();
88
 
89
+ // Step 2.b: Fetch documents and evaluations
90
+ const [documentsPerEvaluation, evaluations] = useMemo(() => {
91
+ // Step 2.b.i: Initialize necessary variables
92
+ const contextsPerEvaluation: Document[][] = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
+ // Step 2.b.i: Fetch evaluations
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  let taskEvaluations: TaskEvaluation[] | undefined = undefined;
96
  if (data) {
97
  taskEvaluations = data.evaluations.filter(
98
  (evaluation) => evaluation.taskId === task.taskId,
99
  );
100
 
101
+ // Step 2.b.i.*: Identify context document for each evaluation and compute context-response overlap and add to evaluation object
102
  taskEvaluations.forEach((evaluation) => {
103
+ const contextDocuments: Document[] = [];
104
+ const contexts = evaluation.contexts
105
+ ? evaluation.contexts
106
+ : task.contexts
107
+ ? task.contexts
108
+ : [];
109
+ if (!isEmpty(contexts)) {
110
+ contexts.forEach((context, contextIdx) => {
111
+ if (data.documents) {
112
+ const referenceDocument = data.documents.find(
113
+ (document) => document.documentId === context.documentId,
114
+ );
115
+ if (referenceDocument) {
116
+ // Step 2.b.i.*: Fetch context relevant annotations, if present
117
+ if (
118
+ task?.annotations &&
119
+ task.annotations.hasOwnProperty('context_relevance')
120
+ ) {
121
+ const documentAnnotation: DocumentAnnotation = {
122
+ text: 'Relevant',
123
+ authors: [],
124
+ color: 'green',
125
+ };
126
+ for (const [annotator, annotations] of Object.entries(
127
+ task.annotations.context_relevance,
128
+ )) {
129
+ if (
130
+ Array.isArray(annotations) &&
131
+ annotations.includes(contextIdx)
132
+ ) {
133
+ documentAnnotation.authors.push(annotator);
134
+ }
135
+ }
136
+ if (!isEmpty(documentAnnotation.authors)) {
137
+ referenceDocument.annotations = [documentAnnotation];
138
+ }
139
+ }
140
+
141
+ contextDocuments.push(referenceDocument);
142
+ } else {
143
+ contextDocuments.push({
144
+ documentId: context.documentId,
145
+ text: 'Missing document text',
146
+ });
147
+ }
148
+ } else {
149
+ contextDocuments.push({
150
+ documentId: context.documentId,
151
+ text: 'Missing document text',
152
+ });
153
+ }
154
+ });
155
+ }
156
+
157
+ // Compute context-response overlap and add to evaluation object
158
  const textOverlaps: StringMatchObject[][] = [];
159
  contextDocuments.forEach((contextDocument) => {
160
  textOverlaps.push(
 
163
  });
164
 
165
  evaluation.overlaps = textOverlaps;
166
+
167
+ // Add context documents
168
+ contextsPerEvaluation.push(contextDocuments);
169
  });
170
  }
171
 
172
+ return [contextsPerEvaluation, taskEvaluations];
173
  }, [task.taskId, task.contexts, data]);
174
 
175
  // Step 2.c: Build human & algorithmic metric maps
 
198
  metrics={metrics}
199
  task={task}
200
  evaluations={evaluations}
201
+ documents={documentsPerEvaluation[selectedEvaluationIndex]}
202
  onClose={() => {
203
  setTaskCopierModalOpen(false);
204
  }}
 
270
  </>
271
  ) : null}
272
  </div>
273
+ {documentsPerEvaluation && (
274
  <div className={classes.contextContainer}>
275
  <div className={classes.header}>
276
  <h4>Contexts</h4>
 
303
  )}
304
  </div>
305
  <DocumentPanel
306
+ key={`evaluation--${selectedEvaluationIndex}__documents`}
307
+ documents={documentsPerEvaluation[
308
+ selectedEvaluationIndex
309
+ ].map((document, documentIdx) => {
310
  return {
311
  documentId: document.documentId,
312
  text: showOverlap
313
  ? mark(
314
  document.text,
315
+ evaluations[selectedEvaluationIndex].overlaps[
316
  documentIdx
317
  ],
318
  'target',
 
342
  <div className={classes.evaluationsContainer}>
343
  <Tabs
344
  onChange={(e) => {
345
+ setSelectedEvaluationIndex(e.selectedIndex);
346
+ setActiveDocumentIndex(0);
347
  }}
348
  >
349
  <TabList
 
362
  ))}
363
  </TabList>
364
  <TabPanels>
365
+ {evaluations.map((evaluation, evaluationIdx) => (
366
  <TabPanel key={'model-' + evaluation.modelId + '-panel'}>
367
  <div className={classes.tabContainer}>
368
  <div className={classes.tabContentHeader}>
 
393
  >
394
  {parse(
395
  DOMPurify.sanitize(
396
+ showOverlap &&
397
+ evaluationIdx === selectedEvaluationIndex
398
  ? mark(
399
  evaluation.modelResponse,
400
  evaluation.overlaps[activeDocumentIndex],
src/views/task/TaskCopier.tsx CHANGED
@@ -262,7 +262,7 @@ export default function TaskCopierModal({
262
  </div>
263
  <span className={classes.heading}>Preview</span>
264
  <CodeSnippet
265
- multi
266
  hideCopyButton={true}
267
  wrapText={true}
268
  className={classes.previewBox}
 
262
  </div>
263
  <span className={classes.heading}>Preview</span>
264
  <CodeSnippet
265
+ type="multi"
266
  hideCopyButton={true}
267
  wrapText={true}
268
  className={classes.previewBox}