Skip to content

Commit

Permalink
Add Exec Results pane for SQL support (#890)
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Seabock (Centific Technologies Inc) <v-ianseabock@microsoft.com>
  • Loading branch information
iseabock and Ian Seabock (Centific Technologies Inc) committed May 31, 2024
1 parent cee4fc1 commit cb65219
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 179 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@
"typescript": "^4.9.5",
"vite": "^4.1.5"
}
}
}
7 changes: 7 additions & 0 deletions frontend/src/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type AskResponse = {
error?: string
message_id?: string
feedback?: Feedback
exec_results?: ExecResults[]
}

export type Citation = {
Expand Down Expand Up @@ -53,6 +54,12 @@ export type ChatMessage = {
context?: string
}

export type ExecResults = {
intent: string
search_query: string | null
search_result: string | null
}

export type Conversation = {
id: string
title: string
Expand Down
34 changes: 29 additions & 5 deletions frontend/src/components/Answer/Answer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import styles from './Answer.module.css'
interface Props {
answer: AskResponse
onCitationClicked: (citedDocument: Citation) => void
onExectResultClicked: () => void
}

export const Answer = ({ answer, onCitationClicked }: Props) => {
export const Answer = ({ answer, onCitationClicked, onExectResultClicked }: Props) => {
const initializeAnswerFeedback = (answer: AskResponse) => {
if (answer.message_id == undefined) return undefined
if (answer.feedback == undefined) return undefined
Expand Down Expand Up @@ -227,7 +228,7 @@ export const Answer = ({ answer, onCitationClicked }: Props) => {
}

const components = {
code({ node, ...props }: { node: any; [key: string]: any }) {
code({ node, ...props }: { node: any;[key: string]: any }) {
let language
if (props.className) {
const match = props.className.match(/language-(\w+)/)
Expand Down Expand Up @@ -268,7 +269,7 @@ export const Answer = ({ answer, onCitationClicked }: Props) => {
onClick={() => onLikeResponseClicked()}
style={
feedbackState === Feedback.Positive ||
appStateContext?.state.feedbackState[answer.message_id] === Feedback.Positive
appStateContext?.state.feedbackState[answer.message_id] === Feedback.Positive
? { color: 'darkgreen', cursor: 'pointer' }
: { color: 'slategray', cursor: 'pointer' }
}
Expand All @@ -279,8 +280,8 @@ export const Answer = ({ answer, onCitationClicked }: Props) => {
onClick={() => onDislikeResponseClicked()}
style={
feedbackState !== Feedback.Positive &&
feedbackState !== Feedback.Neutral &&
feedbackState !== undefined
feedbackState !== Feedback.Neutral &&
feedbackState !== undefined
? { color: 'darkred', cursor: 'pointer' }
: { color: 'slategray', cursor: 'pointer' }
}
Expand Down Expand Up @@ -326,6 +327,29 @@ export const Answer = ({ answer, onCitationClicked }: Props) => {
<Stack.Item className={styles.answerDisclaimerContainer}>
<span className={styles.answerDisclaimer}>AI-generated content may be incorrect</span>
</Stack.Item>
{!!answer.exec_results?.length && (
<Stack.Item onKeyDown={e => (e.key === 'Enter' || e.key === ' ' ? toggleIsRefAccordionOpen() : null)}>
<Stack style={{ width: '100%' }}>
<Stack horizontal horizontalAlign="start" verticalAlign="center">
<Text
className={styles.accordionTitle}
onClick={() => onExectResultClicked()}
aria-label="Open exec results"
tabIndex={0}
role="button">
<span>
Show Exec Results
</span>
</Text>
<FontIcon
className={styles.accordionIcon}
onClick={handleChevronClick}
iconName={'ChevronRight'}
/>
</Stack>
</Stack>
</Stack.Item>
)}
</Stack>
{chevronIsExpanded && (
<div className={styles.citationWrapper}>
Expand Down
27 changes: 27 additions & 0 deletions frontend/src/pages/chat/Chat.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,33 @@
flex-grow: 0;
}

.exectResultList {
display: flex;
flex-direction: column;
gap: 8px;
border-bottom: 1px solid #323130;
margin-top: 12px;
}

.exectResultList:first-child {
margin-top: 0;
}

.exectResultList:last-child {
border-bottom: none;
}

.exectResultList > p {
display: flex;
flex-direction: row;
gap: 4px;
margin: 3px 0;
}

.exectResultList > p > span {
font-weight: 600;
}

a {
padding-left: 5px;
padding-right: 5px;
Expand Down
49 changes: 48 additions & 1 deletion frontend/src/pages/chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
ChatHistoryLoadingState,
CosmosDBStatus,
ErrorMessage,
ExecResults,
AzureSqlServerCodeExecResult
} from "../../api";
import { Answer } from "../../components/Answer";
Expand All @@ -52,9 +53,11 @@ const Chat = () => {
const [showLoadingMessage, setShowLoadingMessage] = useState<boolean>(false)
const [activeCitation, setActiveCitation] = useState<Citation>()
const [isCitationPanelOpen, setIsCitationPanelOpen] = useState<boolean>(false)
const [isIntentsPanelOpen, setIsIntentsPanelOpen] = useState<boolean>(false)
const abortFuncs = useRef([] as AbortController[])
const [showAuthMessage, setShowAuthMessage] = useState<boolean | undefined>()
const [messages, setMessages] = useState<ChatMessage[]>([])
const [execResults, setExecResults] = useState<ExecResults[]>([])
const [processMessages, setProcessMessages] = useState<messageStatus>(messageStatus.NotRunning)
const [clearingChat, setClearingChat] = useState<boolean>(false)
const [hideErrorDialog, { toggle: toggleErrorDialog }] = useBoolean(true)
Expand Down Expand Up @@ -122,6 +125,11 @@ const Chat = () => {
let assistantContent = ''

const processResultMessage = (resultMessage: ChatMessage, userMessage: ChatMessage, conversationId?: string) => {
if (resultMessage.content.includes('all_exec_results')) {
const parsedExecResults = JSON.parse(resultMessage.content) as AzureSqlServerExecResults
setExecResults(parsedExecResults.all_exec_results)
}

if (resultMessage.role === ASSISTANT) {
assistantContent += resultMessage.content
assistantMessage = resultMessage
Expand Down Expand Up @@ -519,6 +527,7 @@ const Chat = () => {
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY', payload: appStateContext?.state.currentChat })
setActiveCitation(undefined)
setIsCitationPanelOpen(false)
setIsIntentsPanelOpen(false)
setMessages([])
}
}
Expand Down Expand Up @@ -584,6 +593,7 @@ const Chat = () => {
setProcessMessages(messageStatus.Processing)
setMessages([])
setIsCitationPanelOpen(false)
setIsIntentsPanelOpen(false)
setActiveCitation(undefined)
appStateContext?.dispatch({ type: 'UPDATE_CURRENT_CHAT', payload: null })
setProcessMessages(messageStatus.Done)
Expand Down Expand Up @@ -671,6 +681,10 @@ const Chat = () => {
setIsCitationPanelOpen(true)
}

const onShowExecResult = () => {
setIsIntentsPanelOpen(true)
}

const onViewSource = (citation: Citation) => {
if (citation.url && !citation.url.includes('blob.core')) {
window.open(citation.url, '_blank')
Expand Down Expand Up @@ -771,9 +785,11 @@ const Chat = () => {
citations: parseCitationFromMessage(messages[index - 1]),
plotly_data: parsePlotFromMessage(messages[index - 1]),
message_id: answer.id,
feedback: answer.feedback
feedback: answer.feedback,
exec_results: execResults
}}
onCitationClicked={c => onShowCitation(c)}
onExectResultClicked={() => onShowExecResult()}
/>
</div>
) : answer.role === ERROR ? (
Expand All @@ -797,6 +813,7 @@ const Chat = () => {
plotly_data: null
}}
onCitationClicked={() => null}
onExectResultClicked={() => null}
/>
</div>
</>
Expand Down Expand Up @@ -941,6 +958,36 @@ const Chat = () => {
</div>
</Stack.Item>
)}
{messages && messages.length > 0 && isIntentsPanelOpen && (
<Stack.Item className={styles.citationPanel} tabIndex={0} role="tabpanel" aria-label="Exec Results Panel">
<Stack
aria-label="Intents Panel Header Container"
horizontal
className={styles.citationPanelHeaderContainer}
horizontalAlign="space-between"
verticalAlign="center">
<span aria-label="Intents" className={styles.citationPanelHeader}>
Exec Results
</span>
<IconButton
iconProps={{ iconName: 'Cancel' }}
aria-label="Close intents panel"
onClick={() => setIsIntentsPanelOpen(false)}
/>
</Stack>
<Stack horizontalAlign="space-between">
{execResults.map((execResult) => {
return (
<Stack className={styles.exectResultList} verticalAlign="space-between">
<p><span>Intent:</span> {execResult.intent}</p>
{execResult.search_query && <p><span>Search Query:</span> {execResult.search_query}</p>}
{execResult.search_result && <p><span>Search Result:</span> {execResult.search_result}</p>}
</Stack>
)
})}
</Stack>
</Stack.Item>
)}
{appStateContext?.state.isChatHistoryOpen &&
appStateContext?.state.isCosmosDBAvailable?.status !== CosmosDBStatus.NotConfigured && <ChatHistoryPanel />}
</Stack>
Expand Down
336 changes: 168 additions & 168 deletions static/assets/index-d0a42b60.js → static/assets/index-1ac4cdd2.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading

0 comments on commit cb65219

Please sign in to comment.