33import { Message , generateId } from 'ai'
44import { useChat } from 'ai/react'
55import { AnimatePresence , m } from 'framer-motion'
6- import { ArrowDown , ArrowUp , Flame , Paperclip , PlugIcon , Square } from 'lucide-react'
6+ import { AlertCircle , ArrowDown , ArrowUp , Flame , Paperclip , PlugIcon , Square } from 'lucide-react'
77import {
88 FormEventHandler ,
99 useCallback ,
@@ -22,6 +22,7 @@ import { requestFileUpload } from '~/lib/util'
2222import { cn } from '~/lib/utils'
2323import { AiIconAnimation } from './ai-icon-animation'
2424import { useApp } from './app-provider'
25+ import ByoLlmButton from './byo-llm-button'
2526import ChatMessage from './chat-message'
2627import { CopyableField } from './copyable-field'
2728import SignInButton from './sign-in-button'
@@ -51,8 +52,17 @@ export function getInitialMessages(tables: TablesData): Message[] {
5152}
5253
5354export default function Chat ( ) {
54- const { user, isLoadingUser, focusRef, setIsSignInDialogOpen, isRateLimited, liveShare } =
55- useApp ( )
55+ const {
56+ user,
57+ isLoadingUser,
58+ focusRef,
59+ setIsSignInDialogOpen,
60+ isRateLimited,
61+ liveShare,
62+ modelProvider,
63+ modelProviderError,
64+ setIsModelProviderDialogOpen,
65+ } = useApp ( )
5666 const [ inputFocusState , setInputFocusState ] = useState ( false )
5767
5868 const {
@@ -155,7 +165,7 @@ export default function Chat() {
155165 cursor : dropZoneCursor ,
156166 } = useDropZone ( {
157167 async onDrop ( files ) {
158- if ( ! user ) {
168+ if ( isAuthRequired ) {
159169 return
160170 }
161171
@@ -223,8 +233,10 @@ export default function Chat() {
223233
224234 const [ isMessageAnimationComplete , setIsMessageAnimationComplete ] = useState ( false )
225235
236+ const isAuthRequired = user === undefined && modelProvider . state ?. enabled !== true
237+
226238 const isChatEnabled =
227- ! isLoadingMessages && ! isLoadingSchema && user !== undefined && ! liveShare . isLiveSharing
239+ ! isLoadingMessages && ! isLoadingSchema && ! isAuthRequired && ! liveShare . isLiveSharing
228240
229241 const isSubmitEnabled = isChatEnabled && Boolean ( input . trim ( ) )
230242
@@ -293,6 +305,42 @@ export default function Chat() {
293305 isLast = { i === messages . length - 1 }
294306 />
295307 ) ) }
308+ < AnimatePresence initial = { false } >
309+ { modelProviderError && ! isLoading && (
310+ < m . div
311+ layout = "position"
312+ className = "flex flex-col gap-4 justify-start items-center max-w-96 p-4 bg-destructive rounded-md text-sm"
313+ variants = { {
314+ hidden : { scale : 0 } ,
315+ show : { scale : 1 , transition : { delay : 0.5 } } ,
316+ } }
317+ initial = "hidden"
318+ animate = "show"
319+ exit = "hidden"
320+ >
321+ < AlertCircle size = { 64 } strokeWidth = { 1 } />
322+ < div className = "flex flex-col items-center text-start gap-4" >
323+ < h3 className = "font-bold" > Whoops!</ h3 >
324+ < p className = "text-center" >
325+ There was an error connecting to your custom model provider:{ ' ' }
326+ { modelProviderError }
327+ </ p >
328+ < p >
329+ Double check your{ ' ' }
330+ < a
331+ className = "underline cursor-pointer"
332+ onClick = { ( ) => {
333+ setIsModelProviderDialogOpen ( true )
334+ } }
335+ >
336+ API info
337+ </ a >
338+ .
339+ </ p >
340+ </ div >
341+ </ m . div >
342+ ) }
343+ </ AnimatePresence >
296344 < AnimatePresence initial = { false } >
297345 { isRateLimited && ! isLoading && (
298346 < m . div
@@ -357,7 +405,7 @@ export default function Chat() {
357405 </ div >
358406 ) : (
359407 < div className = "h-full w-full max-w-4xl flex flex-col gap-10 justify-center items-center" >
360- { user ? (
408+ { ! isAuthRequired ? (
361409 < >
362410 < LiveShareOverlay databaseId = { databaseId } />
363411 < m . h3
@@ -384,11 +432,10 @@ export default function Chat() {
384432 animate = "show"
385433 >
386434 < SignInButton />
387- < p className = "font-lighter text-center" >
388- To prevent abuse we ask you to sign in before chatting with AI.
389- </ p >
435+ or
436+ < ByoLlmButton />
390437 < p
391- className = "underline cursor-pointer text-primary/50"
438+ className = "underline cursor-pointer text-sm text- primary/50"
392439 onClick = { ( ) => {
393440 setIsSignInDialogOpen ( true )
394441 } }
@@ -427,7 +474,7 @@ export default function Chat() {
427474 </ div >
428475 < div className = "flex flex-col items-center gap-3 pb-1 relative" >
429476 < AnimatePresence >
430- { ! user && ! isLoadingUser && isConversationStarted && (
477+ { isAuthRequired && ! isLoadingUser && isConversationStarted && (
431478 < m . div
432479 className = "flex flex-col items-center gap-4 max-w-lg my-4"
433480 variants = { {
@@ -438,9 +485,8 @@ export default function Chat() {
438485 exit = "hidden"
439486 >
440487 < SignInButton />
441- < p className = "font-lighter text-center text-sm" >
442- To prevent abuse we ask you to sign in before chatting with AI.
443- </ p >
488+ or
489+ < ByoLlmButton />
444490 < p
445491 className = "underline cursor-pointer text-sm text-primary/50"
446492 onClick = { ( ) => {
@@ -487,7 +533,7 @@ export default function Chat() {
487533 onClick = { async ( e ) => {
488534 e . preventDefault ( )
489535
490- if ( ! user ) {
536+ if ( isAuthRequired ) {
491537 return
492538 }
493539
0 commit comments