You are on page 1of 11

import React, {

useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import {
Paper,
Stack,
Typography,
Button,
TextField,
Box,
} from '@mui/material';
import {
// dateIsValid as isValidDate,
validateDateRangeFilter,
} from 'utils/validations';

import AssignmentOutlinedIcon from '@mui/icons-material/AssignmentOutlined';


import { ApprovalDialog } from 'components/search/dictionary/ApprovalDialog';
import { R_MODELS_CONFIGURATION } from 'routes/route_constants';
import { showAlert } from 'store/actions/alert';
import { useApi, useAppId, useQuery } from 'hooks';
import theme from 'theme';
import { ModelType } from 'components/models/types';
import { MLOpsService } from 'services';
import { modelsApis } from 'apiEndpoints';
import {
GetDateRangeFilter,
getDateRange,
} from 'components/reusable/GetDateRangeFilter';
import { useSearchParams } from 'react-router-dom';
import { StoreType } from 'store/types/store/state';
import { startDate as START_DATE_ACTION } from 'store/actions/dates';
import { dateIsValid as isValidDate } from 'utils/validations';
import { DateRange } from '@mui/lab';
import { useSelector } from 'react-redux';
import { Debounce } from 'utils/debounce';
import NEROverview from './NEROverview';

interface IOverviewProps {
modelType: ModelType;
text?: string | React.ReactNode;
}

export type State = {


userQueries: unknown[];
field_config: any[];

overviewType: string | undefined;


summaryList: unknown[];
summaryFieldConfig: any[];
graph: {
data_points: { x: string; y: number }[];
x_axis_field: string;
y_axis_field: string[];
data_key: { key: string; label: string }[];
};
isGraphLoading: boolean;
selectedMetrics?: string[];
};
export const Overview = (props: IOverviewProps) => {
const { text, modelType } = props;
const defaultSearchMetrics =
modelType === 'RANKING'
? ['ndcg_views']
: [
'oov_query_frequency',
// 'total_search_term_frequency',
];
const createExperimentAPI = useApi(MLOpsService.createExperiment);
const experimentsGridAPI = useApi(MLOpsService.experimentsGrid);
const createNERViewMetricsAPI = useApi(MLOpsService.createNERViewMetrics);
const createCLSViewMetricsAPI = useApi(MLOpsService.createCLSViewMetrics);
const createRankingViewMetricsApi = useApi(
MLOpsService.createRankingViewMetrics
);

const apiMapping: any = {


NER: createNERViewMetricsAPI,
CLS: createCLSViewMetricsAPI,
RANKING: createRankingViewMetricsApi,
};

const { loading } = createExperimentAPI;


const onboardingReducer = useSelector(
(store: StoreType) => store.onboardingReducer
);
const clickStreamEnabled =
onboardingReducer?.getAppSettingsConfig?.data?.click_stream_enabled ||
false;
const dispatch = useDispatch();
const [searchParams] = useSearchParams();
const [state, setState] = useState<any>(() => ({
userQueries: [],
field_config: [],
// page: pageFromSearchParams || 0,
// page_size: pageSizeFromSearchParams || 25,
// loading: false,
// showTopUserQueriesDrawer: false,
// searchText: '',
// isSearchTextAdded: false,
// sortBy: '',
// sortOrder: -1,
// total: 0,
overviewType: 'total_searches',
summaryList: [],
summaryFieldConfig: [],
graph: {
data_points: [{ x: '', y: 0 }],
x_axis_field: '',
y_axis_field: [],
data_key: [],
},
isGraphLoading: false,
isFileDownLoadInitiated: false,
selectedMetrics: defaultSearchMetrics,
}));

const query = useQuery();


const start = query.get('start_date');
const end = query.get('end_date');
const type = query.get('type');
const dateStart = searchParams.get('dateStart');
const dateEnd = searchParams.get('dateEnd');
const dateType = searchParams.get('dateType');
useEffect(() => {
if (dateStart && dateEnd && dateType) {
dispatch(
START_DATE_ACTION({
start_date: dateStart,
end_date: dateEnd,
date_type: dateType,
})
);
}
}, [dateStart, dateEnd, dateType]);

const dateFromStorage = useSelector((state: StoreType) => state.dateReducer);


const start_date =
(isValidDate(dateFromStorage?.start_date?.toString()) &&
new Date(dateFromStorage?.start_date)?.toISOString()) ||
(isValidDate(dateStart?.toString()) && new Date(dateStart)?.toISOString());
const end_date =
(isValidDate(dateFromStorage?.end_date?.toString()) &&
new Date(dateFromStorage?.end_date)?.toISOString()) ||
(isValidDate(dateEnd?.toString()) && new Date(dateEnd)?.toISOString());
const [selectedDateRange, setSelectedDateRange] = useState(
dateFromStorage?.date_type || type || dateType || 'last_7_days'
);
const [selectedCustomDateRange, setSelectedCustomDateRange] = React.useState<
DateRange<Date>
>([
(start_date && new Date(start_date)) ||
(start && new Date(start)) ||
new Date(),
(end_date && new Date(end_date)) || (end && new Date(end)) || new Date(),
]);
const [showDatePicker, setShowDatePicker] = useState(false);
const selectedDateRangeRef = useRef(selectedDateRange);
const selectedCustomDateRangeRef = useRef(selectedCustomDateRange);

const navigate = useNavigate();


const getAppId = useAppId('search');
// const [showDatePicker, setShowDatePicker] = useState(false);
const selectWorkspace = useSelector(
(store: StoreType) => store.selectWorkspace
);
const [openModal, setOpenModal] = useState(false);
const [experimentName, setExperimentName] = useState('');
// const experimentsGridData = experimentsGridAPI?.data?.data?.data;

const { startDate, endDate } = useMemo(


() => getDateRange(selectedDateRange, selectedCustomDateRange),
[selectedDateRange, selectedCustomDateRange]
);

const handleCreateExperiment = () => {


createExperimentAPI
.request({
data: {
params: {
app_id: getAppId,
model_type: modelType,
name: experimentName,
},
},
})
.then(res => {
dispatch(
showAlert({
message: 'Experiment created successfully',
severity: 'success',
})
);
navigate(
`${R_MODELS_CONFIGURATION(modelType.toLowerCase())}?exp_id=${
res?.data?.data?._id
}`
);
setOpenModal(false);
});
};
const handleOverviewGraphApiCall = (postData?: any) => {
if (modelType === 'NER' || modelType === 'CLS' || modelType === 'RANKING') {
const payload = {
data: {
metrics_type:
modelType === 'RANKING' ? ['OVERVIEW_GRAPH'] : ['OVERVIEW'],
view_type: 'GRAPH',
app_id: getAppId,
clickstream: clickStreamEnabled,
...postData,
},
};
if (
selectWorkspace?.applications?.length > 0 &&
((selectedDateRangeRef.current === 'custom' &&
!validateDateRangeFilter(
selectedDateRangeRef.current,
selectedCustomDateRangeRef.current[0],
selectedCustomDateRangeRef.current[1]
)?.error) ||
selectedDateRangeRef.current !== 'custom')
) {
setState((prev: State) => ({ ...prev, isGraphLoading: true }));
// createNERViewMetricsAPI
apiMapping[modelType]
?.request(payload)
.then((res: any) => {
const dataKey: Set<string> = new Set();
const graphLabel =
modelType === 'RANKING' ? 'OVERVIEW_GRAPH' : 'OVERVIEW';

if (res?.data?.[graphLabel]?.data)
res?.data?.[graphLabel]?.data?.graph?.data_points?.forEach(
(data: any) => {
Object.keys(data).forEach(key => {
if (key !== 'date') {
dataKey.add(key);
}
});
}
);

setState((prev: State) => ({


...prev,
graph: {
data_points: res?.data?.[graphLabel].data?.graph?.data_points,
x_axis_field:
res?.data?.[graphLabel]?.data?.graph?.x_axis_field,
y_axis_field:
res?.data?.[graphLabel]?.data?.graph?.y_axis_field,
data_key: res?.data?.[graphLabel]?.data
? Array.from(dataKey)?.map((key: string) => ({
key,
label:
res?.data?.[graphLabel]?.meta?.field_config?.find(
(field: any) => field?.field_name === key
)?.label || key,
// color:
// index >= segmentColors?.length
// ? getRandomColor()
// : segmentColors[index],
}))
: [],
},
summaryList: res?.data?.[graphLabel].data?.summary,
summaryFieldConfig: res?.data?.[graphLabel]?.meta?.field_config,
isGraphLoading: false,
}));
})
.catch((errors: { msg: string }[]) => {
dispatch(
showAlert({
message: errors?.[0]?.msg || 'Something Went Wrong!',
severity: 'error',
})
);
setState((prev: State) => ({
...prev,
isGraphLoading: false,
}));
});
}
}
};
const dateRangeProps = {
selectedCustomDateRange,
selectedDateRange,
showDatePicker,
setShowDatePicker,
setSelectedDateRange,
setSelectedCustomDateRange,
};

useEffect(() => {
if (getAppId && modelType) {
experimentsGridAPI.request({
params: {
path: modelsApis.GET_EXPERIMENT_DETAILS,
method: 'POST',
},
data: {
payload: {
app_id: getAppId,
model_type: modelType.toUpperCase(),
// ...postData,
},
},
});
}
}, []);
const graphCall = useCallback(Debounce(handleOverviewGraphApiCall, 500), []);
const graphPayload = {
// filters: [],
start_date: startDate,
end_date: endDate,
app_id: getAppId,
clickstream: clickStreamEnabled,
pagination: {
page: state.page,
page_size: state.page_size,
},
// filters:
// state.selectedMetrics?.length > 0
// ? [{ y_field: state.selectedMetrics.map((item: any) => item) }]
// : [
// {
// y_field: [],
// },
// ],
};

useEffect(() => {
if (selectedDateRange === 'custom') {
graphCall(graphPayload);
} else {
handleOverviewGraphApiCall(graphPayload);
}
}, [selectedCustomDateRange, selectedDateRange]);
selectedDateRangeRef.current = selectedDateRange;
selectedCustomDateRangeRef.current = selectedCustomDateRange;

// const graphfilteredData = state?.graph?.data_points.map((item: any) => {


// const filteredItem: any = {};
// filteredItem.date = item?.date;

// for (const metric of state?.selectedMetrics) {


// if (item.hasOwnProperty(metric)) {
// filteredItem[metric] = item[metric];
// }
// }

// return filteredItem;
// });

// const selectedObjects = state?.graph?.data_key.filter((item: any) =>


// state?.selectedMetrics.includes(item.key)
// );
return (
<Paper
elevation={0}
sx={{
background: theme.palette.common.white,
border: `1px solid ${theme.palette.grey[300]}`,
// height: 'calc(100vh - 190px)',
// height: 'calc(100vh - 120px)',
// height: 'fit-content',
padding: '31px 24px',
}}
>
{experimentsGridAPI?.data?.data?.data?.length === 0 ||
(['SPELL'].includes(modelType) && (
<Stack>
<Stack direction="column" gap={4}>
<Typography
sx={{
fontWeight: theme.typography.customFontWeight.medium,
fontSize: theme.typography.customFontSize.xxxl,
}}
>
{modelType} Model Training
</Typography>
<Stack direction="row" gap={2}>
<Stack gap={3}>
<AssignmentOutlinedIcon
sx={{
fontSize: '10rem',
}}
/>
<Button
variant="outlined"
disableRipple
sx={{
width: 'fit-content',
fontSize: theme.typography.customFontSize.sm,
fontWeight: theme.typography.customFontWeight.regular,
}}
onClick={() => setOpenModal(true)}
>
Start Configuration
</Button>
</Stack>
<Stack
direction="column"
sx={{
gap: '0.5rem',
}}
>
<Typography
sx={{
fontWeight: theme.typography.customFontWeight.medium,
fontSize: theme.typography.customFontSize.md,
}}
>
Train your first model
</Typography>
<Stack
sx={{
height: 'calc(100vh - 290px)',
overflow: 'auto',
width: '500px',
}}
spacing={1}
>
{text}
</Stack>
</Stack>
</Stack>
</Stack>
</Stack>
))}
{/* {experimentsGridAPI?.data?.data?.data?.length !== 0 &&
(modelType === 'NER' || modelType === 'CLS') &&
state?.summaryFieldConfig?.length > 0 && (
<Stack width="210px" direction="row" pt={2}>
<MetricsDropdown
options={state?.summaryFieldConfig?.filter(
(item: any) => item?.selectable
)}
defaultMetrics={['total_search_term_frequency']}
title="Maximum 5"
selectedMatchCriteria={state.selectedMetrics}
setSelectedMatchCriteria={(value: any) =>
setState((prev: State) => ({
...prev,
selectedMetrics: value,
}))
}
/>
</Stack>
)}
{experimentsGridAPI?.data?.data?.data?.length !== 0 &&
modelType === 'NER' && (
<Stack pt={2} flexGrow={1} sx={{ '.recharts-surface': { p: 0.3 } }}>
{state.isGraphLoading ? (
<Skeleton
height="150px"
sx={{
borderRadius: '6px',
flexGrow: 1,
// width: isSidebarOpen
// ? 'calc(100vw - 300px)'
// : 'calc(100vw - 145px)',
}}
animation="wave"
/>
) : (
<>
<SearchLineChart
isCustomToolTip
customToolTip={
<CustomLineChartTooltip
active={undefined}
payload={undefined}
label={undefined}
title="Metrics"
matchCriteria={
state?.field_config?.filter(
(item: any) =>
item.selectable &&
item?.field_name === state?.selectedMetrics
)?.[0]?.label || ''
}
/>
}
dx={-5}
lineData={selectedObjects?.map((item: any, index: any) => ({
dataKey: item?.key,
XAxisLabel: item?.label,
stroke: segmentColors[index],
}))}
width="100%"
height="100%"
margin={{ margin: 30 }}
data={graphfilteredData}
XDataKey="date"
YAxisLabel={
state?.graph?.y_axis_field?.length > 1
? 'Metrics'
: state?.summaryFieldConfig?.filter(
(item: any) =>
item?.field_name === state?.graph?.y_axis_field?.[0]
)?.[0]?.label
}
containerHeight={230}
// YAxisLabel={
// state?.graph?.y_axis_field?.length > 1
// ? 'metrics'
// : state?.graph?.y_axis_field?.[0]
// }
/>
</>
)}
</Stack>
)}
<Divider sx={{ mt: 2 }} />
{experimentsGridAPI?.data?.data?.data?.length !== 0 &&
(modelType === 'NER' || modelType === 'CLS') && (
<Stack mt={2}>
<TopSearches
queryType="OVERVIEW"
searchAndFilterNeeded
mainAPI={apiMapping[modelType]}
dateRangeProps={dateRangeProps}
isDefaultColumnsNeeded
defaultColumns={[
'search_term',
'ner',
'model_id',
'total_searches',
'clicks',
'cr',
'ctr',
]}
/>
<Stack gap={2} mt={2} direction="row">
<Stack>
<TopSearches
queryType="OVERVIEW_OOV_WORDS"
mainAPI={apiMapping[modelType]}
tableWidth="calc(50vw - 186px)"
minWidth={350}
dateRangeProps={dateRangeProps}
defaultColumns={['oov_word', 'frequency']}
/>
</Stack>
<Stack>
<TopSearches
queryType="OVERVIEW_OOV_QUERIES"
mainAPI={apiMapping[modelType]}
tableWidth="calc(50vw - 186px)"
minWidth={350}
dateRangeProps={dateRangeProps}
defaultColumns={['search_term', 'frequency']}
/>
</Stack>
</Stack>
</Stack>
)} */}
{experimentsGridAPI?.data?.data?.data?.length !== 0 &&
['NER', 'CLS', 'RANKING']?.includes(modelType) &&
modelType?.length > 0 && (
<NEROverview
experimentsGridAPI={
experimentsGridAPI?.data?.data?.data?.length !== 0
}
modelType={modelType}
state={state}
setState={setState}
dateRangeProps={dateRangeProps}
apiMapping={apiMapping}
/>
)}
{/* <CLSOverview
experimentsGridAPI={experimentsGridAPI}
modelType={modelType}
state={state}
setState={setState}
dateRangeProps={dateRangeProps}
apiMapping={apiMapping}
/> */}
<ApprovalDialog
open={openModal}
approveBtnText="Create"
handleClose={() => {
setOpenModal(false);
// setAnchorEl(null);
// setId('');
}}
validateData={() => experimentName?.length === 0}
handleApproval={handleCreateExperiment}
title="Experiment Name"
loading={loading}
>
<Stack spacing={1}>
<Stack>
<Typography
sx={{
fontSize: theme.typography.customFontSize.sm,
fontWeight: theme.typography.customFontWeight.regular,
color: theme.palette.text.secondary,
}}
>
Enter a name for the experiment
</Typography>
</Stack>
<Stack spacing={0.5}>
<Typography
sx={{
fontSize: theme.typography.customFontSize.sm,
fontWeight: theme.typography.customFontWeight.semiBold,
}}
>
Experiment Name
</Typography>
<TextField
placeholder="Enter Name"
value={experimentName}
onChange={e => setExperimentName(e.target.value)}
/>
</Stack>
</Stack>
</ApprovalDialog>
{experimentsGridAPI?.data?.data?.data?.length !== 0 &&
(modelType === 'NER' ||
modelType === 'CLS' ||
modelType === 'RANKING') && (
<Box sx={{ position: 'absolute', right: '2%', top: '4px' }}>
<GetDateRangeFilter {...dateRangeProps} />
</Box>
)}
</Paper>
);
};

You might also like