Skip to content

Commit

Permalink
add error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
chihebnabil committed Nov 22, 2024
1 parent c2f17dd commit 6a9939a
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 82 deletions.
18 changes: 6 additions & 12 deletions components/ChatMessage.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
<template>
<div
:class="[
<div :class="[
'flex mb-4 max-w-full',
message.role === 'user' ? 'justify-end' : 'justify-start'
]">
<div
:class="[
<div :class="[
'flex items-start max-w-[85%]',
message.role === 'user' ? 'flex-row-reverse' : ''
]">
<UAvatar
:src="message.role === 'user' ? '/user-avatar.png' : '/assistant-avatar.png'"
:alt="message.role === 'user' ? 'User' : 'AI'" size="sm" class="flex-shrink-0"/>
<UAvatar :alt="message.role === 'user' ? 'User' : 'AI'" size="sm" class="flex-shrink-0" />
<div class="flex flex-col mx-2">
<div
:class="[
<div :class="[
'px-4 py-2 rounded-lg break-words',
message.role === 'user'
? 'bg-primary text-white dark:bg-primary-600'
: 'bg-gray-200 dark:bg-gray-700 dark:text-gray-100'
]" v-html="$mdRenderer.render(message.content)"/>
<span
:class="[
]" v-html="$mdRenderer.render(message.content)" />
<span :class="[
'text-xs mt-1',
message.role === 'user' ? 'text-right' : 'text-left',
'text-gray-500 dark:text-gray-400'
Expand Down
160 changes: 93 additions & 67 deletions components/MessageInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { ref } from 'vue'
const route = useRoute()
const { loader } = useLoader()
const { messages } = useApp()
const toast = useToast()
const props = defineProps({
attachedFiles: {
Expand Down Expand Up @@ -102,82 +103,107 @@ const removeFile = async (fileToRemove) => {
}
const handleSendMessage = async () => {
if (inputMessage.value.trim() !== '') {
// Add user message
const userMessage = {
id: messages.value.length + 1,
createdAt: new Date(),
content: inputMessage.value,
role: 'user'
}
messages.value.push(userMessage)
// Create assistant message placeholder for streaming
const assistantMessage = {
id: messages.value.length + 2,
createdAt: new Date(),
content: '', // Will be updated as we receive chunks
role: 'assistant'
}
loader.value = true
if (inputMessage.value.trim() === '') return
// Add user message
const userMessage = {
id: messages.value.length + 1,
createdAt: new Date(),
content: inputMessage.value,
role: 'user'
}
messages.value.push(userMessage)
// Create assistant message placeholder for streaming
const assistantMessage = {
id: messages.value.length + 2,
createdAt: new Date(),
content: '', // Will be updated as we receive chunks
role: 'assistant'
}
messages.value.push(assistantMessage)
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: inputMessage.value,
threadId: route.params.id,
selectedFiles: selectedFiles.value
})
loader.value = true
const messageContent = inputMessage.value
inputMessage.value = '' // Clear input after sending
try {
// Use regular fetch for streaming
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: messageContent,
threadId: route.params.id,
selectedFiles: selectedFiles.value
})
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
// Clear input after sending
inputMessage.value = ''
const reader = response.body.getReader()
const decoder = new TextDecoder()
messages.value.push(assistantMessage)
try {
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value, { stream: true })
const lines = chunk.split('\n')
for (const line of lines) {
if (line.trim() && line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(5))
if (data.type === 'content_block_delta' && data.delta?.text) {
// Update the last messages item with the new content
messages.value[messages.value.length - 1].content += data.delta.text
// delay to allow the UI to update
await new Promise(resolve => setTimeout(resolve, 100))
}
} catch (e) {
console.error('Error parsing SSE data:', e)
const reader = response.body.getReader()
const decoder = new TextDecoder()
try {
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value, { stream: true })
const lines = chunk.split('\n')
for (const line of lines) {
if (line.trim() && line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(5))
if (data.type === 'content_block_delta' && data.delta?.text) {
// Update the last messages item with the new content
messages.value[messages.value.length - 1].content += data.delta.text
// delay to allow the UI to update
await new Promise(resolve => setTimeout(resolve, 100))
}
} catch (e) {
console.error('Error parsing SSE data:', e)
toast.add({
title: 'Error',
description: 'Error parsing response data',
color: 'red',
timeout: 5000,
icon: 'i-heroicons-exclamation-circle'
})
}
}
}
} catch (error) {
console.error('Error reading stream:', error)
// remove assistant message
messages.value.pop()
}
} catch (error) {
console.error('Error sending message:', error)
} finally {
loader.value = false
} catch (streamError) {
console.error('Error reading stream:', streamError)
toast.add({
title: 'Error',
description: 'Error reading response stream',
color: 'red',
timeout: 5000,
icon: 'i-heroicons-exclamation-circle'
})
// remove assistant message on error
messages.value.pop()
}
} catch (error) {
console.error('Error sending message:', error)
toast.add({
title: 'Error',
description: error.message || 'Failed to send message',
color: 'red',
timeout: 5000,
icon: 'i-heroicons-exclamation-circle'
})
// remove assistant message on error
messages.value.pop()
} finally {
loader.value = false
}
}
</script>
4 changes: 1 addition & 3 deletions server/api/logs/index.get.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import db from "~/server/utils/db";
import { eq, count , desc } from "drizzle-orm";
import { eq, count, desc } from "drizzle-orm";
import { logs } from "~/server/database/schema";

export default defineEventHandler(async (event) => {
Expand Down Expand Up @@ -30,8 +30,6 @@ export default defineEventHandler(async (event) => {
.offset(offset)
.orderBy(desc(logs.id));

console.log(items);

return {
items,
pagination: {
Expand Down

0 comments on commit 6a9939a

Please sign in to comment.