Skip to content

Commit

Permalink
Merge pull request #2958 from the-deep/feature/restriction-auto-clust…
Browse files Browse the repository at this point in the history
…ering

Restriction on auto clustering and remove restriction on auto extractions
  • Loading branch information
AdityaKhatri authored Jun 13, 2024
2 parents 4643781 + d39b118 commit 49df55c
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 51 deletions.
11 changes: 1 addition & 10 deletions app/components/LeftPaneEntries/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import {
import { GeoArea } from '#components/GeoMultiSelectInput';
import LeadPreview from '#components/lead/LeadPreview';
import Screenshot from '#components/Screenshot';
import ProjectContext from '#base/context/ProjectContext';
import { UserContext } from '#base/context/UserContext';
import {
LeadPreviewForTextQuery,
Expand Down Expand Up @@ -159,7 +158,6 @@ function LeftPane(props: Props) {
} = props;

const alert = useAlert();
const { project } = useContext(ProjectContext);
const { user } = useContext(UserContext);

const isAssistedTaggingAccessible = !!user
Expand Down Expand Up @@ -556,23 +554,17 @@ function LeftPane(props: Props) {
});
}, []);

const assistedTaggingShown = !project?.isPrivate
&& isAssistedTaggingAccessible
const assistedTaggingShown = isAssistedTaggingAccessible
&& frameworkDetails?.assistedTaggingEnabled
&& (frameworkDetails?.predictionTagsMapping?.length ?? 0) > 0;

const isAutoExtractionCompatible = isDefined(leadPreview?.textExtractionId)
&& leadPreviewData?.project?.lead?.confidentiality !== 'CONFIDENTIAL'
&& assistedTaggingShown;

const errorMessageForAutoExtraction = useMemo(() => {
const isConfidential = lead?.confidentiality === 'CONFIDENTIAL';
if (isAutoExtractionCompatible) {
return undefined;
}
if (isConfidential) {
return 'The feature to extract entries through Natural Language Processing (NLP) is currently unavailable for the selected source. Extraction through NLP is restricted for confidential sources to ensure the utmost data security and privacy.';
}
if (isDefined(leadPreviewData?.project?.lead?.connectorLead)) {
return 'The feature to extract entries through Natural Language Processing (NLP) is currently unavailable for the selected source. The connector associated with the chosen source may be outdated or incompatible with the NLP extraction functionality.';
}
Expand All @@ -581,7 +573,6 @@ function LeftPane(props: Props) {
}
return 'The feature to extract entries through Natural Language Processing (NLP) is currently unavailable for the selected source. The selected source appears to be outdated, and the NLP extraction feature is not compatible with older content formats.';
}, [
lead?.confidentiality,
isAutoExtractionCompatible,
leadPreviewData?.project?.lead,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import MarkdownEditor from '#components/MarkdownEditor';
import { organizationTitleSelector } from '#components/selections/NewOrganizationSelectInput';
import { GeoArea } from '#components/GeoMultiSelectInput';
import SourcesFilterContext from '#components/leadFilters/SourcesFilterContext';
import ProjectContext from '#base/context/ProjectContext';

import EntryCard from './EntryCard';
import EntryContext from '../../context';
Expand Down Expand Up @@ -132,6 +133,9 @@ function StoryAnalysisModal(props: Props) {
informationGaps: informationGapsFromProps,
} = props;

const {
project,
} = useContext(ProjectContext);
const { entries } = useContext(EntryContext);
const { organizationTypeOptions } = useContext(SourcesFilterContext);

Expand Down Expand Up @@ -377,6 +381,7 @@ function StoryAnalysisModal(props: Props) {
className={styles.tab}
name="summary"
transparentBorder
disabled={project?.isPrivate}
>
Automatic Summary
</Tab>
Expand Down Expand Up @@ -431,7 +436,10 @@ function StoryAnalysisModal(props: Props) {
/>
</div>
</TabPanel>
<TabPanel name="summary" className={styles.tabPanel}>
<TabPanel
name="summary"
className={styles.tabPanel}
>
<Summary
projectId={projectId}
summaryId={automaticSummaryId}
Expand Down
172 changes: 134 additions & 38 deletions app/views/PillarAnalysis/AnalyticalStatementInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useMemo } from 'react';
import React, { useState, useContext, useCallback, useMemo } from 'react';
import {
IoClose,
IoCheckmarkCircleSharp,
Expand Down Expand Up @@ -38,9 +38,14 @@ import {
getErrorObject,
} from '@togglecorp/toggle-form';
import { gql, useMutation } from '@apollo/client';
import ProjectContext from '#base/context/ProjectContext';
import {
AutomaticStoryAnalysisMutation,
AutomaticStoryAnalysisMutationVariables,
AnalysisAutomaticSummaryMutation,
AnalysisAutomaticSummaryMutationVariables,
AnalysisGeoLocationMutation,
AnalysisGeoLocationMutationVariables,
AnalysisAutomaticNgramMutation,
AnalysisAutomaticNgramMutationVariables,
} from '#generated/types';

import MarkdownEditor from '#components/MarkdownEditor';
Expand All @@ -64,27 +69,9 @@ import styles from './styles.css';

export const ENTRIES_LIMIT = 200;

const AUTOMATIC_STORY_ANALYSIS = gql`
mutation AutomaticStoryAnalysis($projectId: ID!, $entriesId: [ID!]) {
const ANALYSIS_AUTOMATIC_NGRAM = gql`
mutation AnalysisAutomaticNgram($projectId: ID!, $entriesId: [ID!]) {
project(id: $projectId) {
triggerAnalysisGeoLocation(data: {entriesId: $entriesId}) {
errors
ok
result {
id
status
entryGeo {
data {
meta {
latitude
longitude
offsetEnd
offsetStart
}
}
}
}
}
triggerAnalysisAutomaticNgram(data: {entriesId: $entriesId}) {
errors
ok
Expand All @@ -105,6 +92,38 @@ const AUTOMATIC_STORY_ANALYSIS = gql`
}
}
}
}
}
`;

const ANALYSIS_GEO_LOCATION = gql`
mutation AnalysisGeoLocation($projectId: ID!, $entriesId: [ID!]) {
project(id: $projectId) {
triggerAnalysisGeoLocation(data: {entriesId: $entriesId}) {
errors
ok
result {
id
status
entryGeo {
data {
meta {
latitude
longitude
offsetEnd
offsetStart
}
}
}
}
}
}
}
`;

const ANALYSIS_AUTOMATIC_SUMMARY = gql`
mutation AnalysisAutomaticSummary($projectId: ID!, $entriesId: [ID!]) {
project(id: $projectId) {
triggerAnalysisAutomaticSummary(data: {entriesId: $entriesId}) {
errors
ok
Expand Down Expand Up @@ -170,6 +189,10 @@ function AnalyticalStatementInput(props: AnalyticalStatementInputProps) {
onEntryDataChange,
} = props;

const {
project,
} = useContext(ProjectContext);

const [selectedField, setSelectedField] = useState<Field | undefined>('statement');
const [selectedContent, setSelectedContent] = useState<Content | undefined>('entries');

Expand All @@ -190,19 +213,17 @@ function AnalyticalStatementInput(props: AnalyticalStatementInputProps) {
] = useModalState(false);

const [
createAutomaticStoryAnalysis,
createAnalysisAutomaticSummary,
{
data: automaticStoryAnalysis,
data: analysisAutomaticSummary,
},
] = useMutation<AutomaticStoryAnalysisMutation, AutomaticStoryAnalysisMutationVariables>(
AUTOMATIC_STORY_ANALYSIS,
] = useMutation<AnalysisAutomaticSummaryMutation, AnalysisAutomaticSummaryMutationVariables>(
ANALYSIS_AUTOMATIC_SUMMARY,
{
onCompleted: (response) => {
if (
!response
|| !response.project?.triggerAnalysisAutomaticNgram
|| !response.project?.triggerAnalysisAutomaticSummary
|| !response.project?.triggerAnalysisGeoLocation
) {
return;
}
Expand All @@ -213,15 +234,67 @@ function AnalyticalStatementInput(props: AnalyticalStatementInputProps) {
{ variant: 'error' },
);
}
if (response.project.triggerAnalysisAutomaticNgram.errors) {
},
onError: () => {
alert.show(
'Failed to create automatic story analysis.',
{ variant: 'error' },
);
},
},
);

const [
createAnalysisGeoLocation,
{
data: analysisGeoLocation,
},
] = useMutation<AnalysisGeoLocationMutation, AnalysisGeoLocationMutationVariables>(
ANALYSIS_GEO_LOCATION,
{
onCompleted: (response) => {
if (
!response
|| !response.project?.triggerAnalysisGeoLocation
) {
return;
}

if (response.project.triggerAnalysisGeoLocation.errors) {
alert.show(
'There were errors when creating automatic Ngram.',
'There were errors when creating geo location.',
{ variant: 'error' },
);
}
if (response.project.triggerAnalysisGeoLocation.errors) {
},
onError: () => {
alert.show(
'Failed to create automatic geo location.',
{ variant: 'error' },
);
},
},
);

const [
createAnalysisAutomaticNgram,
{
data: analysisAutomaticNgram,
},
] = useMutation<AnalysisAutomaticNgramMutation, AnalysisAutomaticNgramMutationVariables>(
ANALYSIS_AUTOMATIC_NGRAM,
{
onCompleted: (response) => {
if (
!response
|| !response.project?.triggerAnalysisAutomaticNgram
) {
return;
}

if (response.project.triggerAnalysisAutomaticNgram.errors) {
alert.show(
'There were errors when extracting geo locations.',
'There were errors when creating automatic Ngram.',
{ variant: 'error' },
);
}
Expand All @@ -236,14 +309,37 @@ function AnalyticalStatementInput(props: AnalyticalStatementInputProps) {
);

const handleStoryAnalysisModalOpen = useCallback(() => {
createAutomaticStoryAnalysis({
if (!project?.isPrivate) {
createAnalysisAutomaticSummary({
variables: {
projectId,
entriesId: value.entries?.map((ae) => ae.entry).filter(isDefined),
},
});
}
createAnalysisGeoLocation({
variables: {
projectId,
entriesId: value.entries?.map((ae) => ae.entry).filter(isDefined),
},
});
createAnalysisAutomaticNgram({
variables: {
projectId,
entriesId: value.entries?.map((ae) => ae.entry).filter(isDefined),
},
});

showStoryAnalysisModal();
}, [value.entries, showStoryAnalysisModal, projectId, createAutomaticStoryAnalysis]);
}, [
value.entries,
project,
showStoryAnalysisModal,
projectId,
createAnalysisAutomaticSummary,
createAnalysisGeoLocation,
createAnalysisAutomaticNgram,
]);

const {
// setValue: onAnalyticalEntryChange,
Expand Down Expand Up @@ -626,11 +722,11 @@ function AnalyticalStatementInput(props: AnalyticalStatementInputProps) {
statementId={value.clientId}
analyticalEntries={value.entries}
projectId={projectId}
automaticSummaryId={automaticStoryAnalysis
automaticSummaryId={analysisAutomaticSummary
?.project?.triggerAnalysisAutomaticSummary?.result?.id}
automaticNgramsId={automaticStoryAnalysis
automaticNgramsId={analysisAutomaticNgram
?.project?.triggerAnalysisAutomaticNgram?.result?.id}
automaticNlpMapId={automaticStoryAnalysis
automaticNlpMapId={analysisGeoLocation
?.project?.triggerAnalysisGeoLocation?.result?.id}
onRemove={onAnalyticalEntryRemove}
index={index}
Expand Down
8 changes: 6 additions & 2 deletions app/views/PillarAnalysis/AutoClustering/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ interface Props {
projectId: string;
entriesCount: number | null | undefined;
entriesFilter: EntriesFilterDataInputType;
isPrivateProject?: boolean;
onEntriesMappingChange: React.Dispatch<React.SetStateAction<Obj<Entry>>>;
onStatementsFromClustersSet: (newStatements: PartialAnalyticalStatementType[]) => void;
}
Expand All @@ -132,6 +133,7 @@ function AutoClustering(props: Props) {
projectId,
entriesFilter,
entriesCount,
isPrivateProject,
onEntriesMappingChange,
onStatementsFromClustersSet,
} = props;
Expand Down Expand Up @@ -351,8 +353,10 @@ function AutoClustering(props: Props) {
className={styles.clusterButton}
name={undefined}
onConfirm={handleAutoClusteringTriggerClick}
message="Are you sure you want to trigger auto clustering of entries into new stories? This will replace current analytical statements with suggested groupings using NLP."
disabled={pendingAutoClusterTrigger || ((entriesCount ?? 0) < MIN_ENTRIES)}
message="Are you sure you want to trigger auto clustering of entries into new stories? This will replace current analytical statements with suggested groupings using NLP. Entries from confidential sources are filtered out to maintain document privacy."
disabled={pendingAutoClusterTrigger
|| ((entriesCount ?? 0) < MIN_ENTRIES)
|| isPrivateProject}
variant="tertiary"
spacing="compact"
title={buttonTitle}
Expand Down
Loading

0 comments on commit 49df55c

Please sign in to comment.