Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

fix: LSDV-5526: Fix duplication of classifications in LLM scenario #1535

Merged
merged 10 commits into from
Sep 8, 2023
1 change: 1 addition & 0 deletions src/regions/Area.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const ClassificationArea = types.compose(
types
.model({
object: types.late(() => types.reference(types.union(...Registry.objectTypes()))),
// true only for global classifications
classification: true,
})
.actions(() => ({
Expand Down
40 changes: 36 additions & 4 deletions src/stores/Annotation/Annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
FF_DEV_2100,
FF_DEV_2100_A,
FF_DEV_2432,
FF_DEV_3391,
FF_DEV_3391, FF_LLM_EPIC,
FF_LSDV_3009,
FF_LSDV_4583,
FF_LSDV_4832,
Expand Down Expand Up @@ -1033,6 +1033,7 @@ export const Annotation = types

self.suggestions.clear();

if (!rawSuggestions) return;
self.deserializeResults(rawSuggestions, {
suggestions: true,
});
Expand Down Expand Up @@ -1274,12 +1275,41 @@ export const Annotation = types

acceptSuggestion(id) {
const item = self.suggestions.get(id);
let itemId = id;
const isGlobalClassification = item.classification;

// this piece of code prevents from creating duplicated global classifications
if (isFF(FF_LLM_EPIC)) {
Gondragos marked this conversation as resolved.
Show resolved Hide resolved
if (isGlobalClassification) {
const itemResult = item.results[0];
const areasIterator = self.areas.values();

for (const area of areasIterator) {
const areaResult = area.results[0];
const isFound = areaResult.from_name === itemResult.from_name
&& areaResult.to_name === itemResult.to_name
&& areaResult.item_index === itemResult.item_index;

if (isFound) {
itemId = area.id;
break;
}
}
} else {
const area = self.areas.get(item.cleanId);

if (area) {
itemId = area.id;
}
}
}

self.areas.set(id, {
self.areas.set(itemId, {
...item.toJSON(),
id: itemId,
fromSuggestion: true,
});
const area = self.areas.get(id);
const area = self.areas.get(itemId);
const activeStates = area.object.activeStates();

activeStates.forEach(state => {
Expand All @@ -1290,8 +1320,10 @@ export const Annotation = types
// hack to unlock sending textarea results
// to the ML backen every time
// it just sets `fromSuggestion` back to `false`
const isTextArea = area.results.findIndex(r => r.type === 'textarea') >= 0;
const isTextArea = area.results.findIndex(r => r.type === 'textarea') >= 0;

// This is temporary exception until we find the way to do it right
// and this was done to keep notifications on prompt editing or fixing answer from ML backend
yyassi-heartex marked this conversation as resolved.
Show resolved Hide resolved
if (isTextArea) area.revokeSuggestion();
},

Expand Down
73 changes: 73 additions & 0 deletions tests/functional/data/lmm/accept_suggestions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { LabelStudio } from '@heartexlabs/ls-test/helpers/LSF';

export const llmTextareaConfig = `<View>
<Style>
.lsf-main-content.lsf-requesting .prompt::before { content: ' loading...'; color: #808080; }
</Style>
<View className="prompt">
<TextArea name="prompt" toName="text" editable="true" rows="2" maxSubmissions="1" showSubmitButton="false"/>
</View>
<Text name="text" value="$text"/>
<TextArea name="answer" toName="text"/>
</View>`;
export const llmTextareaData = { text: 'Some simple text' };

export const LLM_WHAT_DO_YOU_SEE = {
prompt: 'What do you see?',
answer: 'I see your question!',
};
export const LLM_WHAT_ELSE_DO_YOU_SEE = {
prompt: 'What else do you see?',
answer: 'Oh! I see some simple text!',
};
export const llmTextareaSuggestions = {
[LLM_WHAT_DO_YOU_SEE.prompt]:
[
{
'from_name': 'prompt',
'id': 'ID_FROM_ML_PROMPT_1',
'to_name': 'text',
'type': 'textarea',
'value': {
'text': [
LLM_WHAT_DO_YOU_SEE.prompt,
],
},
},
{
'from_name': 'answer',
'id': 'ID_FROM_ML_ANSWER_1',
'to_name': 'text',
'type': 'textarea',
'value': {
'text': [
LLM_WHAT_DO_YOU_SEE.answer,
],
},
},
],
[LLM_WHAT_ELSE_DO_YOU_SEE.prompt]: [
{
'from_name': 'prompt',
'id': 'ID_FROM_ML_PROMPT_2',
'to_name': 'text',
'type': 'textarea',
'value': {
'text': [
LLM_WHAT_ELSE_DO_YOU_SEE.prompt,
],
},
},
{
'from_name': 'answer',
'id': 'ID_FROM_ML_ANSWER_2',
'to_name': 'text',
'type': 'textarea',
'value': {
'text': [
LLM_WHAT_ELSE_DO_YOU_SEE.answer,
],
},
},
],
};
1 change: 1 addition & 0 deletions tests/functional/feature-flags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as FLAGS from '../../src/utils/feature-flags';

export const CURRENT_FLAGS = {
[FLAGS.FF_DEV_1284]: true,
[FLAGS.FF_DEV_1170]: true,
[FLAGS.FF_PROD_309]: true,
[FLAGS.FF_LSDV_4930]: true,
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"cvg:summary": "nyc report --temp-dir=.nyc_output --reporter=text-summary --cwd=. --exclude-after-remap false"
},
"dependencies": {
"@heartexlabs/ls-test": "git+ssh://[email protected]/heartexlabs/ls-frontend-test#579c0060d388a7a49f896a3b71373be45782ea6a"
"@heartexlabs/ls-test": "git+ssh://[email protected]/heartexlabs/ls-frontend-test#df936d7caf911e4ef91ab9eefc828267b71460c1"
},
"devDependencies": {
"ts-loader": "^9.4.2",
Expand Down
54 changes: 54 additions & 0 deletions tests/functional/specs/llm/accept_suggestions.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { LabelStudio, useTextarea } from '@heartexlabs/ls-test/helpers/LSF';
import {
LLM_WHAT_DO_YOU_SEE, LLM_WHAT_ELSE_DO_YOU_SEE,
llmTextareaConfig,
llmTextareaData,
llmTextareaSuggestions
} from 'data/lmm/accept_suggestions';
import { FF_DEV_1284, FF_LLM_EPIC } from '../../../../src/utils/feature-flags';

function getLLMSuggestions(area, connectedRegions) {
const prompt = area?.results?.[0]?.value?.text?.[0];

if (prompt) {
const suggestions = llmTextareaSuggestions[prompt];

setTimeout(() => {
area.store.loadSuggestions(new Promise((resolve) => setTimeout(() => {
resolve(suggestions);
}, 1000)), x => x);
}, 1000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why so long? can we reduce it to make it go faster?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We surely can, but I don't know if it catch the problem when it appears.

}
}

describe('LLM scenario', () => {
beforeEach(() => {
LabelStudio.addFeatureFlagsOnPageLoad({
[FF_LLM_EPIC]: true,
});
});

it('Accept suggestions - TextArea', () => {

LabelStudio.params()
.config(llmTextareaConfig)
.data(llmTextareaData)
.withResult([])
.withInterface('auto-annotation')
.withEventListener('regionFinishedDrawing', getLLMSuggestions)
.withParam('forceAutoAnnotation', true)
.init();
const promptTextAarea = useTextarea('&:eq(0)');
const answerTextArea = useTextarea('&:eq(1)');

promptTextAarea.type(`${LLM_WHAT_DO_YOU_SEE.prompt}{shift+enter}`);
answerTextArea.hasValue(LLM_WHAT_DO_YOU_SEE.answer);
promptTextAarea.clickRowEdit(1);
promptTextAarea.rowType(1, `{selectAll}{backspace}${LLM_WHAT_ELSE_DO_YOU_SEE.prompt}{shift+enter}`);
answerTextArea.hasValue(LLM_WHAT_ELSE_DO_YOU_SEE.answer);

LabelStudio.serialize().then((result) => {
hlomzik marked this conversation as resolved.
Show resolved Hide resolved
expect(result.length).to.be.equal(2);
});
});
});
22 changes: 22 additions & 0 deletions tests/functional/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,28 @@
webpack-cli "^5.0.1"
yargs "^17.7.1"

"@heartexlabs/ls-test@git+ssh://[email protected]/heartexlabs/ls-frontend-test#df936d7caf911e4ef91ab9eefc828267b71460c1":
version "1.0.8"
resolved "git+ssh://[email protected]/heartexlabs/ls-frontend-test#df936d7caf911e4ef91ab9eefc828267b71460c1"
dependencies:
"@cypress/code-coverage" "^3.10.0"
"@cypress/webpack-preprocessor" "^5.17.0"
chai "^4.3.7"
cypress "^12.9.0"
cypress-image-snapshot "^4.0.1"
cypress-multi-reporters "^1.6.2"
cypress-parallel "^0.12.0"
cypress-plugin-snapshots "^1.4.4"
cypress-terminal-report "^5.1.1"
pixelmatch "^5.3.0"
pngjs "^7.0.0"
proper-lockfile "^4.1.2"
ts-loader "^9.4.2"
typescript "^4.9.5"
webpack "^5.77.0"
webpack-cli "^5.0.1"
yargs "^17.7.1"

"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
Expand Down
Loading