Skip to content

Commit

Permalink
feat: error handler & show error message
Browse files Browse the repository at this point in the history
  • Loading branch information
ddiu8081 committed Mar 16, 2023
1 parent 1a0db57 commit ccd4c97
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 9 deletions.
24 changes: 24 additions & 0 deletions src/components/ErrorMessageItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ErrorMessage } from '@/types'
import IconRefresh from './icons/Refresh'

interface Props {
data: ErrorMessage
onRetry?: () => void
}

export default ({ data, onRetry }: Props) => {
return (
<div class="my-4 px-4 py-3 border border-red/50 bg-red/10">
{data.code && <div class="text-red mb-1">{data.code}</div>}
<div class="text-red op-70 text-sm">{data.message}</div>
{onRetry && (
<div class="fie px-3 mb-2">
<div onClick={onRetry} class="gpt-retry-btn border-red/50 text-red">
<IconRefresh />
<span>Regenerate</span>
</div>
</div>
)}
</div>
)
}
13 changes: 10 additions & 3 deletions src/components/Generator.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { ChatMessage } from '@/types'
import type { ChatMessage, ErrorMessage } from '@/types'
import { createSignal, Index, Show, onMount, onCleanup } from 'solid-js'
import IconClear from './icons/Clear'
import MessageItem from './MessageItem'
import SystemRoleSettings from './SystemRoleSettings'
import ErrorMessageItem from './ErrorMessageItem'
import { generateSignature } from '@/utils/auth'
import { useThrottleFn } from 'solidjs-use'

Expand All @@ -11,6 +12,7 @@ export default () => {
const [currentSystemRoleSettings, setCurrentSystemRoleSettings] = createSignal('')
const [systemRoleEditing, setSystemRoleEditing] = createSignal(false)
const [messageList, setMessageList] = createSignal<ChatMessage[]>([])
const [currentError, setCurrentError] = createSignal<ErrorMessage>()
const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal('')
const [loading, setLoading] = createSignal(false)
const [controller, setController] = createSignal<AbortController>(null)
Expand Down Expand Up @@ -64,6 +66,7 @@ export default () => {
const requestWithLatestMessage = async () => {
setLoading(true)
setCurrentAssistantMessage('')
setCurrentError(null)
const storagePassword = localStorage.getItem('pass')
try {
const controller = new AbortController()
Expand All @@ -90,7 +93,10 @@ export default () => {
signal: controller.signal,
})
if (!response.ok) {
throw new Error(response.statusText)
const error = await response.json()
console.error(error.error)
setCurrentError(error.error)
throw new Error('Request failed')
}
const data = response.body
if (!data) {
Expand Down Expand Up @@ -160,8 +166,8 @@ export default () => {
console.log(lastMessage)
if (lastMessage.role === 'assistant') {
setMessageList(messageList().slice(0, -1))
requestWithLatestMessage()
}
requestWithLatestMessage()
}
}

Expand Down Expand Up @@ -199,6 +205,7 @@ export default () => {
message={currentAssistantMessage}
/>
)}
{ currentError() && <ErrorMessageItem data={currentError()} onRetry={retryLastFetch} /> }
<Show
when={!loading()}
fallback={() => (
Expand Down
30 changes: 25 additions & 5 deletions src/pages/api/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@ export const post: APIRoute = async (context) => {
const body = await context.request.json()
const { sign, time, messages, pass } = body
if (!messages) {
return new Response('No input text')
return new Response(JSON.stringify({
error: {
message: 'No input text.',
}
}), { status: 400 })
}
if (sitePassword && sitePassword !== pass) {
return new Response('Invalid password')
return new Response(JSON.stringify({
error: {
message: 'Invalid password.',
}
}), { status: 401 })
}
if (import.meta.env.PROD && !await verifySignature({ t: time, m: messages?.[messages.length - 1]?.content || '', }, sign)) {
return new Response('Invalid signature')
return new Response(JSON.stringify({
error: {
message: 'Invalid signature.',
}
}), { status: 401 })
}
const initOptions = generatePayload(apiKey, messages)
// #vercel-disable-blocks
Expand All @@ -30,7 +42,15 @@ export const post: APIRoute = async (context) => {
// #vercel-end

// @ts-ignore
const response = await fetch(`${baseUrl}/v1/chat/completions`, initOptions) as Response
const response = await fetch(`${baseUrl}/v1/chat/completions`, initOptions).catch((err: Error) => {
console.error(err)
return new Response(JSON.stringify({
error: {
code: err.name,
message: err.message,
}
}), { status: 500 })
}) as Response

return new Response(parseOpenAIStream(response))
return parseOpenAIStream(response) as Response
}
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ export interface ChatMessage {
role: 'system' | 'user' | 'assistant'
content: string
}

export interface ErrorMessage {
code: string
message: string
}
8 changes: 7 additions & 1 deletion src/utils/openAI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export const generatePayload = (apiKey: string, messages: ChatMessage[]): Reques
export const parseOpenAIStream = (rawResponse: Response) => {
const encoder = new TextEncoder()
const decoder = new TextDecoder()
if (!rawResponse.ok) {
return new Response(rawResponse.body, {
status: rawResponse.status,
statusText: rawResponse.statusText,
})
}

const stream = new ReadableStream({
async start(controller) {
Expand Down Expand Up @@ -57,5 +63,5 @@ export const parseOpenAIStream = (rawResponse: Response) => {
},
})

return stream
return new Response(stream)
}

1 comment on commit ccd4c97

@vercel
Copy link

@vercel vercel bot commented on ccd4c97 Mar 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.