2
0

🐛 Fix streaming text selection (#1444)

This commit is contained in:
Baptiste Arnaud
2024-04-12 11:02:28 +02:00
committed by GitHub
parent d608a30e47
commit 3f367800df
10 changed files with 52 additions and 25 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/js",
"version": "0.2.70",
"version": "0.2.71",
"description": "Javascript library to display typebots on your website",
"type": "module",
"main": "dist/index.js",

View File

@ -154,6 +154,7 @@ export const ConversationContainer = (props: Props) => {
const longRequest = setTimeout(() => {
setIsSending(true)
}, 1000)
autoScrollToBottom()
const { data, error } = await continueChatQuery({
apiHost: props.context.apiHost,
sessionId: props.initialChatReply.sessionId,
@ -205,6 +206,11 @@ export const ConversationContainer = (props: Props) => {
isNotDefined(action.lastBubbleBlockId)
)
await processClientSideActions(actionsBeforeFirstBubble)
if (
data.clientSideActions.length === 1 &&
data.clientSideActions[0].type === 'stream'
)
return
}
setChatChunks((displayedChunks) => [
...displayedChunks,

View File

@ -1,5 +1,5 @@
import { streamingMessage } from '@/utils/streamingMessageSignal'
import { createEffect, createSignal } from 'solid-js'
import { For, createEffect, createSignal } from 'solid-js'
import { marked } from 'marked'
import domPurify from 'dompurify'
@ -8,7 +8,7 @@ type Props = {
}
export const StreamingBubble = (props: Props) => {
const [content, setContent] = createSignal<string>('')
const [content, setContent] = createSignal<string[]>([])
marked.use({
renderer: {
@ -19,12 +19,16 @@ export const StreamingBubble = (props: Props) => {
})
createEffect(() => {
if (streamingMessage()?.id === props.streamingMessageId)
setContent(
domPurify.sanitize(marked.parse(streamingMessage()?.content ?? ''), {
ADD_ATTR: ['target'],
})
)
if (streamingMessage()?.id !== props.streamingMessageId) return []
setContent(
streamingMessage()
?.content.split('\n\n')
.map((line) =>
domPurify.sanitize(marked.parse(line), {
ADD_ATTR: ['target'],
})
) ?? []
)
})
return (
@ -43,8 +47,9 @@ export const StreamingBubble = (props: Props) => {
class={
'flex flex-col overflow-hidden text-fade-in mx-4 my-2 relative text-ellipsis h-full gap-6'
}
innerHTML={content()}
/>
>
<For each={content()}>{(line) => <span innerHTML={line} />}</For>
</div>
</div>
</div>
</div>

View File

@ -7,16 +7,22 @@ let abortController: AbortController | null = null
const secondsToWaitBeforeRetries = 3
const maxRetryAttempts = 3
const edgeRuntimePath = '/api/integrations/openai/streamer'
const nodejsRuntimePath = (sessionId: string) =>
`/api/v1/sessions/${sessionId}/streamMessage`
export const streamChat =
(context: ClientSideActionContext & { retryAttempt?: number }) =>
async ({
messages,
runtime,
onMessageStream,
}: {
messages?: {
content?: string | undefined
role?: 'system' | 'user' | 'assistant' | undefined
}[]
runtime: 'edge' | 'nodejs'
onMessageStream?: (props: { id: string; message: string }) => void
}): Promise<{ message?: string; error?: object }> => {
try {
@ -25,9 +31,12 @@ export const streamChat =
const apiHost = context.apiHost
const res = await fetch(
`${
isNotEmpty(apiHost) ? apiHost : guessApiHost()
}/api/integrations/openai/streamer`,
isNotEmpty(apiHost)
? apiHost
: guessApiHost() +
(runtime === 'edge'
? edgeRuntimePath
: nodejsRuntimePath(context.sessionId)),
{
method: 'POST',
headers: {
@ -35,7 +44,7 @@ export const streamChat =
},
body: JSON.stringify({
messages,
sessionId: context.sessionId,
sessionId: runtime === 'edge' ? context.sessionId : undefined,
}),
signal: abortController.signal,
}
@ -52,7 +61,7 @@ export const streamChat =
return streamChat({
...context,
retryAttempt: (context.retryAttempt ?? 0) + 1,
})({ messages, onMessageStream })
})({ messages, onMessageStream, runtime })
}
return {
error: (await res.json()) || 'Failed to fetch the chat response.',

View File

@ -54,12 +54,17 @@ export const executeClientSideAction = async ({
'streamOpenAiChatCompletion' in clientSideAction ||
'stream' in clientSideAction
) {
const runtime =
'streamOpenAiChatCompletion' in clientSideAction
? clientSideAction.streamOpenAiChatCompletion.runtime
: clientSideAction.runtime
const { error, message } = await streamChat(context)({
messages:
'streamOpenAiChatCompletion' in clientSideAction
? clientSideAction.streamOpenAiChatCompletion?.messages
: undefined,
onMessageStream,
runtime,
})
if (error)
return {

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/nextjs",
"version": "0.2.70",
"version": "0.2.71",
"description": "Convenient library to display typebots on your Next.js website",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@ -1,6 +1,6 @@
{
"name": "@typebot.io/react",
"version": "0.2.70",
"version": "0.2.71",
"description": "Convenient library to display typebots on your React app",
"main": "dist/index.js",
"types": "dist/index.d.ts",