Skip to content

Commit 04303a9

Browse files
Chat mode entity show (#504)
* Chat mode entity show * Legend changes * chat-mode-changes * schema changes
1 parent 11d8beb commit 04303a9

File tree

11 files changed

+148
-93
lines changed

11 files changed

+148
-93
lines changed

backend/src/QA_integration_new.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,8 @@ def QA_RAG(graph, model, question, session_id, mode):
285285
"model": model_version,
286286
"chunkdetails": result["chunkdetails"],
287287
"total_tokens": total_tokens,
288-
"response_time": 0
288+
"response_time": 0,
289+
"mode": mode
289290
},
290291
"user": "chatbot"
291292
}
@@ -299,7 +300,8 @@ def QA_RAG(graph, model, question, session_id, mode):
299300
"info": {
300301
"sources": [],
301302
"chunkids": [],
302-
"error": f"{error_name} :- {str(e)}"
303+
"error": f"{error_name} :- {str(e)}",
304+
"mode": mode
303305
},
304306
"user": "chatbot"
305307
}

frontend/src/components/ChatBot/Info/InfoModal.tsx renamed to frontend/src/components/ChatBot/ChatInfoModal.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
import { Box, Typography, TextLink, Flex, Tabs, LoadingSpinner } from '@neo4j-ndl/react';
22
import { DocumentTextIconOutline } from '@neo4j-ndl/react/icons';
3-
import '../../../styling/info.css';
4-
import Neo4jRetrievalLogo from '../../../assets/images/Neo4jRetrievalLogo.png';
5-
import wikipedialogo from '../../../assets/images/wikipedia.svg';
6-
import youtubelogo from '../../../assets/images/youtube.svg';
7-
import gcslogo from '../../../assets/images/gcs.webp';
8-
import s3logo from '../../../assets/images/s3logo.png';
9-
import { Chunk, Entity, GroupedEntity, UserCredentials, chatInfoMessage } from '../../../types';
3+
import '../../styling/info.css';
4+
import Neo4jRetrievalLogo from '../../assets/images/Neo4jRetrievalLogo.png';
5+
import wikipedialogo from '../../assets/images/wikipedia.svg';
6+
import youtubelogo from '../../assets/images/youtube.svg';
7+
import gcslogo from '../../assets/images/gcs.webp';
8+
import s3logo from '../../assets/images/s3logo.png';
9+
import { Chunk, Entity, GroupedEntity, UserCredentials, chatInfoMessage } from '../../types';
1010
import { useEffect, useMemo, useState } from 'react';
11-
import HoverableLink from '../../UI/HoverableLink';
12-
import GraphViewButton from '../../Graph/GraphViewButton';
13-
import { chunkEntitiesAPI } from '../../../services/ChunkEntitiesInfo';
14-
import { useCredentials } from '../../../context/UserCredentials';
11+
import HoverableLink from '../UI/HoverableLink';
12+
import GraphViewButton from '../Graph/GraphViewButton';
13+
import { chunkEntitiesAPI } from '../../services/ChunkEntitiesInfo';
14+
import { useCredentials } from '../../context/UserCredentials';
1515
import type { Node, Relationship } from '@neo4j-nvl/base';
1616
import { calcWordColor } from '@neo4j-devtools/word-color';
1717
import ReactMarkdown from 'react-markdown';
1818
import { GlobeAltIconOutline } from '@neo4j-ndl/react/icons';
19-
import { youtubeLinkValidation } from '../../../utils/Utils';
20-
const InfoModal: React.FC<chatInfoMessage> = ({ sources, model, total_tokens, response_time, chunk_ids }) => {
19+
import { youtubeLinkValidation } from '../../utils/Utils';
20+
21+
const ChatInfoModal: React.FC<chatInfoMessage> = ({ sources, model, total_tokens, response_time, chunk_ids, mode }) => {
2122
const [activeTab, setActiveTab] = useState<number>(3);
2223
const [infoEntities, setInfoEntities] = useState<Entity[]>([]);
2324
const [loading, setLoading] = useState<boolean>(false);
@@ -98,15 +99,16 @@ const InfoModal: React.FC<chatInfoMessage> = ({ sources, model, total_tokens, re
9899
<Box className='flex flex-col'>
99100
<Typography variant='h2'>Retrieval information</Typography>
100101
<Typography variant='body-medium' className='mb-2'>
101-
To generate this response, in <span className='font-bold'>{response_time} seconds</span> we used{' '}
102-
<span className='font-bold'>{total_tokens}</span> tokens with the model{' '}
103-
<span className='font-bold'>{model}</span>.
102+
To generate this response, the process took <span className='font-bold'>{response_time} seconds,</span>{' '}
103+
utilizing <span className='font-bold'>{total_tokens}</span> tokens with the model{' '}
104+
<span className='font-bold'>{model}</span> in{' '}
105+
<span className='font-bold'>{mode !== 'vector' ? mode.replace(/\+/g, ' & ') : mode}</span> mode.
104106
</Typography>
105107
</Box>
106108
</Box>
107109
<Tabs size='large' fill='underline' onChange={onChangeTabs} value={activeTab}>
108110
<Tabs.Tab tabId={3}>Sources used</Tabs.Tab>
109-
<Tabs.Tab tabId={4}>Top Entities used</Tabs.Tab>
111+
{mode === 'graph+vector' && <Tabs.Tab tabId={4}>Top Entities used</Tabs.Tab>}
110112
<Tabs.Tab tabId={5}>Chunks</Tabs.Tab>
111113
</Tabs>
112114
<Flex className='p-4'>
@@ -349,4 +351,4 @@ const InfoModal: React.FC<chatInfoMessage> = ({ sources, model, total_tokens, re
349351
</Box>
350352
);
351353
};
352-
export default InfoModal;
354+
export default ChatInfoModal;

frontend/src/components/ChatBot/Chatbot.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { useCredentials } from '../../context/UserCredentials';
1212
import { chatBotAPI } from '../../services/QnaAPI';
1313
import { v4 as uuidv4 } from 'uuid';
1414
import { useFileContext } from '../../context/UsersFiles';
15-
import InfoModal from './Info/InfoModal';
15+
import InfoModal from './ChatInfoModal';
1616
import clsx from 'clsx';
1717
import ReactMarkdown from 'react-markdown';
1818
import IconButtonWithToolTip from '../UI/IconButtonToolTip';
@@ -35,6 +35,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
3535
const [chunkModal, setChunkModal] = useState<chunk[]>([]);
3636
const [tokensUsed, setTokensUsed] = useState<number>(0);
3737
const [copyMessageId, setCopyMessageId] = useState<number | null>(null);
38+
const [chatsMode, setChatsMode] = useState<string>('graph+vector');
3839

3940
const [value, copy] = useCopyToClipboard();
4041
const { speak, cancel } = useSpeechSynthesis({
@@ -63,6 +64,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
6364
response_time?: number;
6465
speaking?: boolean;
6566
copying?: boolean;
67+
mode?: string;
6668
},
6769
index = 0
6870
) => {
@@ -89,6 +91,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
8991
response_time: response?.response_time,
9092
speaking: false,
9193
copying: false,
94+
mode: response?.mode,
9295
},
9396
]);
9497
} else {
@@ -107,6 +110,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
107110
lastmsg.response_time = response?.response_time;
108111
lastmsg.speaking = false;
109112
lastmsg.copying = false;
113+
lastmsg.mode = response?.mode;
110114
return msgs.map((msg, index) => {
111115
if (index === msgs.length - 1) {
112116
return lastmsg;
@@ -136,6 +140,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
136140
let chatChunks;
137141
let chatTimeTaken;
138142
let chatTokensUsed;
143+
let chatingMode;
139144
const datetime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
140145
const userMessage = { id: Date.now(), user: 'user', message: inputMessage, datetime: datetime };
141146
setListMessages([...listMessages, userMessage]);
@@ -151,6 +156,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
151156
chatChunks = chatresponse?.data?.data?.info.chunkdetails;
152157
chatTokensUsed = chatresponse?.data?.data?.info.total_tokens;
153158
chatTimeTaken = chatresponse?.data?.data?.info.response_time;
159+
chatingMode = chatresponse?.data?.data?.info?.mode;
154160
const finalbotReply = {
155161
reply: chatbotReply,
156162
sources: chatSources,
@@ -160,6 +166,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
160166
response_time: chatTimeTaken,
161167
speaking: false,
162168
copying: false,
169+
mode: chatingMode,
163170
};
164171
simulateTypingEffect(finalbotReply);
165172
} catch (error) {
@@ -304,6 +311,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
304311
setChunkModal(chat.chunk_ids ?? []);
305312
setTokensUsed(chat.total_tokens ?? 0);
306313
setShowInfoModal(true);
314+
setChatsMode(chat.mode ?? '');
307315
}}
308316
>
309317
{' '}
@@ -394,6 +402,7 @@ const Chatbot: React.FC<ChatbotProps> = (props) => {
394402
chunk_ids={chunkModal}
395403
response_time={responseTime}
396404
total_tokens={tokensUsed}
405+
mode={chatsMode}
397406
/>
398407
</Modal>
399408
</div>

frontend/src/components/Content.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,13 @@ const Content: React.FC<ContentProps> = ({
337337
[selectedfileslength, completedfileNo]
338338
);
339339

340-
const processingCheck = () => {
341-
const processingFiles = filesData.some((file) => file.status === 'Processing');
342-
const selectedRowProcessing = selectedRows.some((row) =>
343-
filesData.some((file) => file.name === row && file.status === 'Processing')
344-
);
345-
return processingFiles || selectedRowProcessing;
346-
};
340+
// const processingCheck = () => {
341+
// const processingFiles = filesData.some((file) => file.status === 'Processing');
342+
// const selectedRowProcessing = selectedRows.some((row) =>
343+
// filesData.some((file) => file.name === row && file.status === 'Processing')
344+
// );
345+
// return processingFiles || selectedRowProcessing;
346+
// };
347347

348348
const filesForProcessing = useMemo(() => {
349349
let newstatusfiles: CustomFile[] = [];
@@ -418,7 +418,7 @@ const Content: React.FC<ContentProps> = ({
418418
if (storedSchema !== null) {
419419
setIsSchema(JSON.parse(storedSchema));
420420
}
421-
}, []);
421+
}, [isSchema]);
422422

423423
const onClickHandler = () => {
424424
if (isSchema) {
@@ -594,6 +594,14 @@ const Content: React.FC<ContentProps> = ({
594594
) : (
595595
<span className='n-body-small'>Not Connected</span>
596596
)}
597+
<div className='pt-1'>
598+
{!isSchema ? <StatusIndicator type='danger' /> : <StatusIndicator type='success' />}
599+
{isSchema ? (
600+
<span className='n-body-small'>Graph Schema configured</span>
601+
) : (
602+
<span className='n-body-small'>No Graph Schema configured</span>
603+
)}
604+
</div>
597605
</Typography>
598606
</div>
599607
{!connectionStatus ? (
@@ -611,19 +619,6 @@ const Content: React.FC<ContentProps> = ({
611619
</div>
612620
)}
613621
</Flex>
614-
<Flex className='w-full' alignItems='center' flexDirection='row'>
615-
<div className='connectionstatus__container !py-2'>
616-
<span className='h6 px-1'>Schema Settings</span>
617-
<Typography variant='body-medium'>
618-
{!isSchema ? <StatusIndicator type='danger' /> : <StatusIndicator type='success' />}
619-
{isSchema ? (
620-
<span className='n-body-small'>Graph Schema configured</span>
621-
) : (
622-
<span className='n-body-small'>No Graph Schema configured</span>
623-
)}
624-
</Typography>
625-
</div>
626-
</Flex>
627622
<FileTable
628623
isExpanded={isLeftExpanded && isRightExpanded}
629624
connectionStatus={connectionStatus}
@@ -702,7 +697,6 @@ const Content: React.FC<ContentProps> = ({
702697
open={openGraphView}
703698
setGraphViewOpen={setOpenGraphView}
704699
viewPoint={viewPoint}
705-
processingCheck={processingCheck()}
706700
/>
707701
</>
708702
);

frontend/src/components/Dropdown.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { Dropdown } from '@neo4j-ndl/react';
22
import { DropdownProps, OptionType } from '../types';
33
import { useMemo } from 'react';
44
import { capitalize } from '../utils/Utils';
5-
65
interface ReusableDropdownProps extends DropdownProps {
7-
options: string[];
6+
options: string[] | OptionType[];
87
placeholder?: string;
98
defaultValue?: string;
109
children?: React.ReactNode;
1110
view?: 'ContentView' | 'GraphView';
1211
isDisabled: boolean;
12+
value?: OptionType;
1313
}
1414
const DropdownComponent: React.FC<ReusableDropdownProps> = ({
1515
options,
@@ -19,6 +19,7 @@ const DropdownComponent: React.FC<ReusableDropdownProps> = ({
1919
children,
2020
view,
2121
isDisabled,
22+
value,
2223
}) => {
2324
const handleChange = (selectedOption: OptionType | null | void) => {
2425
onSelect(selectedOption);
@@ -32,16 +33,24 @@ const DropdownComponent: React.FC<ReusableDropdownProps> = ({
3233
aria-label='A selection dropdown'
3334
selectProps={{
3435
onChange: handleChange,
35-
options: allOptions?.map((option) => ({
36-
label: option.includes('LLM_MODEL_CONFIG_')
37-
? capitalize(option.split('LLM_MODEL_CONFIG_').at(-1) as string)
38-
: capitalize(option),
39-
value: option,
40-
})),
36+
options: allOptions?.map((option) => {
37+
const label =
38+
typeof option === 'string'
39+
? option.includes('LLM_MODEL_CONFIG_')
40+
? capitalize(option.split('LLM_MODEL_CONFIG_').at(-1) as string)
41+
: capitalize(option)
42+
: capitalize(option.label);
43+
const value = typeof option === 'string' ? option : option.value;
44+
return {
45+
label,
46+
value,
47+
};
48+
}),
4149
placeholder: placeholder || 'Select an option',
4250
defaultValue: defaultValue ? { label: capitalize(defaultValue), value: defaultValue } : undefined,
4351
menuPlacement: 'auto',
4452
isDisabled: isDisabled,
53+
value: value,
4554
}}
4655
size='medium'
4756
fluid

frontend/src/components/Graph/GraphViewModal.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
lexicalGraph,
2727
mouseEventCallbacks,
2828
nvlOptions,
29+
queryMap,
2930
} from '../../utils/Constants';
3031
import { useFileContext } from '../../context/UsersFiles';
3132
// import CheckboxSelection from './CheckboxSelection';
@@ -37,7 +38,6 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
3738
viewPoint,
3839
nodeValues,
3940
relationshipValues,
40-
processingCheck,
4141
}) => {
4242
const nvlRef = useRef<NVL>(null);
4343
const [nodes, setNodes] = useState<Node[]>([]);
@@ -52,6 +52,10 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
5252
const [scheme, setScheme] = useState<Scheme>({});
5353
const { selectedRows } = useFileContext();
5454
const [newScheme, setNewScheme] = useState<Scheme>({});
55+
const [dropdownVal, setDropdownVal] = useState<OptionType>({
56+
label: 'Knowledge Graph',
57+
value: queryMap.DocChunkEntities,
58+
});
5559

5660
// const handleCheckboxChange = (graph: GraphType) => {
5761
// const currentIndex = graphType.indexOf(graph);
@@ -182,9 +186,9 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
182186

183187
// Refresh the graph with nodes and relations if file is processing
184188
const handleRefresh = () => {
185-
setLoading(true);
186-
setGraphType(intitalGraphType);
187189
graphApi();
190+
setGraphType(intitalGraphType);
191+
setDropdownVal({ label: 'Knowledge Graph', value: queryMap.DocChunkEntities });
188192
};
189193

190194
// when modal closes reset all states to default
@@ -242,14 +246,15 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
242246
if (selectedOption?.value) {
243247
const selectedValue = selectedOption.value;
244248
let newGraphType: GraphType[] = [];
245-
if (selectedValue === knowledgeGraph) {
246-
newGraphType = intitalGraphType;
247-
} else if (selectedValue === lexicalGraph) {
248-
newGraphType = ['Document', 'Chunk'];
249-
} else if (selectedValue === entityGraph) {
249+
if (selectedValue === 'entities') {
250250
newGraphType = ['Entities'];
251+
} else if (selectedValue === queryMap.DocChunks) {
252+
newGraphType = ['Document', 'Chunk'];
253+
} else if (selectedValue === queryMap.DocChunkEntities) {
254+
newGraphType = ['Document', 'Entities', 'Chunk'];
251255
}
252256
setGraphType(newGraphType);
257+
setDropdownVal(selectedOption);
253258
initGraph(newGraphType, allNodes, allRelationships, scheme);
254259
}
255260
};
@@ -279,7 +284,8 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
279284
placeholder='Select Graph Type'
280285
defaultValue={getDropdownDefaultValue()}
281286
view='GraphView'
282-
isDisabled={nodes.length === 0 || allNodes.length === 0}
287+
isDisabled={loading}
288+
value={dropdownVal}
283289
/>
284290
)}
285291
</Flex>
@@ -310,7 +316,7 @@ const GraphViewModal: React.FunctionComponent<GraphViewModalProps> = ({
310316
nvlCallbacks={nvlCallbacks}
311317
/>
312318
<IconButtonArray orientation='vertical' floating className='absolute bottom-4 right-4'>
313-
{viewPoint !== 'chatInfoView' && processingCheck && (
319+
{viewPoint !== 'chatInfoView' && (
314320
<IconButtonWithToolTip
315321
label='Refresh'
316322
text='Refresh graph'

frontend/src/components/Graph/LegendsChip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const LegendsChip: React.FunctionComponent<LegendChipProps> = ({ scheme,
66
const chunkcount = useMemo(
77
// @ts-ignore
88
() => [...new Set(nodes?.filter((n) => n?.labels?.includes(title)).map((i) => i.id))].length,
9-
[]
9+
[nodes]
1010
);
1111
return <Legend title={title} chunkCount={chunkcount} bgColor={scheme[title]}></Legend>;
1212
};

0 commit comments

Comments
 (0)