Skip to content

Commit 5a5606f

Browse files
authored
feat: integrate new generate route in Zendesk (#78)
1 parent 8f82798 commit 5a5606f

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

zendesk_app/src/app/components/RightPanelApp/RightPanelApp.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,24 @@ export const RightPanelApp = (): JSX.Element => {
2626
const { quivrService, ingestionStatus, setIngestionStatus, zendeskConnection } = useQuivrApiContext()
2727
const [iterationRequest, setIterationRequest] = useState('')
2828
const { actionButtons, isChatEnabled } = useActionButtons()
29-
const { loading, response, setResponse, submitTask, ticketAnswerId, setTicketAnswerId, isError } =
30-
useExecuteZendeskTaskContext()
29+
const {
30+
loading,
31+
response,
32+
setResponse,
33+
submitTask,
34+
ticketAnswerId,
35+
isAutoDraftDisplayed,
36+
setTicketAnswerId,
37+
isError
38+
} = useExecuteZendeskTaskContext()
3139
const [ongoingTask, setOngoingTask] = useState(false)
3240
const [autoDraft, setAutoDraft] = useState<Autodraft | null>(null)
3341
const { pasteInEditor, getTicketId, getUser } = useZendesk()
3442
const client = useClient() as ZAFClient
3543
const lowConfidenceWarningEnabled = useFeatureFlagEnabled(featureFlags.LOW_CONFIDENCE_WARNING)
44+
const showLowConfidenceWarning = Boolean(
45+
autoDraft && !autoDraft.context_is_enough && lowConfidenceWarningEnabled && isAutoDraftDisplayed && !ongoingTask
46+
)
3647

3748
useEffect(() => {
3849
client.invoke('resize', { width: '100%', height: '450px' })
@@ -127,7 +138,7 @@ export const RightPanelApp = (): JSX.Element => {
127138
</span>
128139
</MessageInfoBox>
129140
)}
130-
{autoDraft && !autoDraft.context_is_enough && lowConfidenceWarningEnabled && (
141+
{showLowConfidenceWarning && (
131142
<MessageInfoBox type="warning">
132143
<span className={styles.error}>
133144
This draft may be incomplete or inaccurate because not all the necessary information is available.
@@ -144,6 +155,7 @@ export const RightPanelApp = (): JSX.Element => {
144155
setResponseContent={setResponse}
145156
ongoingTask={ongoingTask}
146157
ticketAnswerId={ticketAnswerId}
158+
showLowConfidenceWarning={showLowConfidenceWarning}
147159
></ResponseContainer>
148160
</div>
149161
<div className={styles.response_separator}></div>

zendesk_app/src/app/components/RightPanelApp/components/ResponseContainer/ResponseContainer.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface ResponseContainerProps {
2525
autoDraft: Autodraft | null
2626
onCopyDraft: () => Promise<void>
2727
ticketAnswerId?: string
28+
showLowConfidenceWarning: boolean
2829
}
2930

3031
export const ResponseContainer = ({
@@ -33,7 +34,8 @@ export const ResponseContainer = ({
3334
ongoingTask,
3435
autoDraft,
3536
onCopyDraft,
36-
ticketAnswerId
37+
ticketAnswerId,
38+
showLowConfidenceWarning
3739
}: ResponseContainerProps): JSX.Element => {
3840
const [htmlContent, setHtmlContent] = useState('')
3941
const [manualEditing, setManualEditing] = useState(false)
@@ -47,7 +49,6 @@ export const ResponseContainer = ({
4749
const openModal = useModal(client)
4850
const autosendFeedbackModalEnabled = useFeatureFlagEnabled(featureFlags.AUTOSEND_FEEDBACK_MODAL)
4951
const autosendFeedbackEnabled = useFeatureFlagEnabled(featureFlags.AUTOSEND_FEEDBACK)
50-
const lowConfidenceWarningEnabled = useFeatureFlagEnabled(featureFlags.LOW_CONFIDENCE_WARNING)
5152
const showAutosendFeedbackButtons =
5253
autoDraft?.prediction?.is_autosendable &&
5354
autoDraft?.prediction?.is_accepted === null &&
@@ -185,7 +186,7 @@ export const ResponseContainer = ({
185186
return (
186187
<div className={styles.main_container}>
187188
<div
188-
className={`${styles.response_container} ${showAutosendFeedbackButtons ? styles.autosendable : ''} ${!autoDraft?.context_is_enough && lowConfidenceWarningEnabled ? styles.low_confidence : ''}`}
189+
className={`${styles.response_container} ${showAutosendFeedbackButtons ? styles.autosendable : ''} ${showLowConfidenceWarning ? styles.low_confidence : ''}`}
189190
contentEditable={true}
190191
dangerouslySetInnerHTML={{ __html: htmlContent }}
191192
onInput={handleInput}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export const featureFlags = {
22
AUTOSEND_FEEDBACK_MODAL: 'autosend-feedback-modal',
33
AUTOSEND_FEEDBACK: 'autosend-feedback',
4-
LOW_CONFIDENCE_WARNING: 'low-confidence-warning'
4+
LOW_CONFIDENCE_WARNING: 'low-confidence-warning',
5+
GENERATE_V2: 'generate-v2'
56
}

zendesk_app/src/app/contexts/ExecuteZendeskTaskProvider.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { useQuivrApiContext } from '../hooks/useQuivrApiContext'
44
import { useZendesk } from '../hooks/useZendesk'
55
import { ZendeskTask } from '../types/zendesk'
66
import { ZAFClient } from './ClientProvider'
7+
import { featureFlags } from '@constants/feature-flags'
8+
import { useFeatureFlagEnabled } from 'posthog-js/react'
79

810
const agentPrompt = 'Vous êtes un assistant attentionné, votre objectif est de satisfaire la demande du client.'
911

1012
interface ExecuteZendeskTaskContextProps {
1113
loading: boolean
1214
response: string
15+
isAutoDraftDisplayed: boolean
1316
setResponse: (r: string) => void
1417
submitTask: (task: ZendeskTask, options: { iterationRequest?: string; onFinish?: () => void }) => Promise<void>
1518
ticketAnswerId?: string
@@ -33,6 +36,7 @@ export const ExecuteZendeskTaskProvider = ({ children }: { children: ReactNode }
3336
const [ticketAnswerId, setTicketAnswerId] = useState<string | undefined>(undefined)
3437
const [previousTask, setPreviousTask] = useState<{ task: ZendeskTask; chatId: string } | null>(null)
3538
const client = useClient() as ZAFClient
39+
const generateV2Enabled = useFeatureFlagEnabled(featureFlags.GENERATE_V2)
3640

3741
const submitTask = async (task: ZendeskTask, options: { iterationRequest?: string; onFinish?: () => void }) => {
3842
if (!quivrService) return
@@ -56,7 +60,11 @@ export const ExecuteZendeskTaskProvider = ({ children }: { children: ReactNode }
5660
const userInput = await getUserInput(client)
5761
const user = await getUser(client)
5862

59-
await quivrService.executeZendeskTask(
63+
const executeTask = (
64+
generateV2Enabled ? quivrService.executeZendeskTaskV2 : quivrService.executeZendeskTask
65+
).bind(quivrService)
66+
67+
await executeTask(
6068
task,
6169
chatId,
6270
task === 'iterate' && iterationRequest ? iterationRequest : agentPrompt,
@@ -98,6 +106,7 @@ export const ExecuteZendeskTaskProvider = ({ children }: { children: ReactNode }
98106
loading,
99107
response,
100108
setResponse,
109+
isAutoDraftDisplayed: !Boolean(previousTask),
101110
submitTask,
102111
ticketAnswerId,
103112
setTicketAnswerId,

zendesk_app/src/app/services/quivr.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,55 @@ export class QuivrService {
124124
}
125125
}
126126

127+
async executeZendeskTaskV2(
128+
task: ZendeskTask,
129+
chatId: string,
130+
custom_instructions: string,
131+
ticketId: string,
132+
draft_answer: string,
133+
user: ZendeskUser,
134+
onStreamMessage: (message: string, ticketAnswerId?: string) => void,
135+
onStreamError?: (error: string | null) => void
136+
): Promise<string> {
137+
const url = new URL(`${this.apiUrl}/helpdesk-accounts/tickets/${ticketId}/tasks/${task}`)
138+
139+
const response = await fetch(url.toString(), {
140+
method: 'POST',
141+
headers: {
142+
Authorization: `Bearer ${this.quivrApiKey}`,
143+
'Content-Type': 'application/json',
144+
Accept: 'text/event-stream'
145+
},
146+
body: JSON.stringify({
147+
draft_answer: draft_answer,
148+
custom_instructions: custom_instructions,
149+
chat_id: chatId,
150+
zt_input: {
151+
support_agent: {
152+
name: user.name,
153+
email: user.email,
154+
role: user.role,
155+
platform_user_id: user.id
156+
}
157+
}
158+
})
159+
})
160+
161+
if (!response.body) {
162+
throw new Error('ReadableStream not supported or no body in response.')
163+
}
164+
165+
return this.processStream(response.body, onStreamMessage, onStreamError)
166+
}
167+
127168
async executeZendeskTask(
128169
task: ZendeskTask,
129170
chatId: string,
130171
prompt: string,
131172
ticketId: string,
132173
content: string,
133174
user: ZendeskUser,
134-
onStreamMessage: (message: string) => void,
175+
onStreamMessage: (message: string, ticketAnswerId?: string) => void,
135176
onStreamError?: (error: string | null) => void
136177
): Promise<string> {
137178
const url = new URL(`${this.apiUrl}/zendesk/task/${task}`)

0 commit comments

Comments
 (0)