File size: 3,067 Bytes
29ee1c2
972bdb5
3578090
0ef8cba
 
3578090
5856d68
506c5f2
3578090
0e5f52f
 
0ef8cba
0e5f52f
 
 
29ee1c2
93cbd1b
0e5f52f
 
dc06ee7
 
3578090
506c5f2
29ee1c2
0ef8cba
3578090
29ee1c2
3578090
506c5f2
 
 
 
 
3578090
 
 
 
506c5f2
5856d68
29ee1c2
 
 
 
 
0ef8cba
 
 
 
271afa2
0ef8cba
 
271afa2
0ef8cba
 
dc06ee7
5856d68
29ee1c2
 
 
 
 
 
0e5f52f
29ee1c2
 
 
 
 
 
 
 
 
 
93cbd1b
 
 
29ee1c2
0e5f52f
29ee1c2
0ef8cba
 
29ee1c2
 
dc06ee7
 
 
 
93e01b6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { useState, useCallback } from 'react'
import ThemeProvider from '@/components/ThemeProvider'
import MessageAlert from '@/components/MessageAlert'
import ApiKeyAlert from '@/components/ApiKeyAlert'
import StatusIndicator from '@/components/graph/StatusIndicator'
import { healthCheckInterval } from '@/lib/constants'
import { useBackendState } from '@/stores/state'
import { useSettingsStore } from '@/stores/settings'
import { useEffect } from 'react'
import { Toaster } from 'sonner'
import SiteHeader from '@/features/SiteHeader'
import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'

import GraphViewer from '@/features/GraphViewer'
import DocumentManager from '@/features/DocumentManager'
import RetrievalTesting from '@/features/RetrievalTesting'
import ApiSite from '@/features/ApiSite'

import { Tabs, TabsContent } from '@/components/ui/Tabs'

function App() {
  const message = useBackendState.use.message()
  const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
  const [currentTab] = useState(() => useSettingsStore.getState().currentTab)
  const [apiKeyInvalid, setApiKeyInvalid] = useState(false)

  // Health check
  useEffect(() => {
    if (!enableHealthCheck) return

    // Check immediately
    useBackendState.getState().check()

    const interval = setInterval(async () => {
      await useBackendState.getState().check()
    }, healthCheckInterval * 1000)
    return () => clearInterval(interval)
  }, [enableHealthCheck])

  const handleTabChange = useCallback(
    (tab: string) => useSettingsStore.getState().setCurrentTab(tab as any),
    []
  )

  useEffect(() => {
    if (message) {
      if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) {
        setApiKeyInvalid(true)
        return
      }
    }
    setApiKeyInvalid(false)
  }, [message, setApiKeyInvalid])

  return (
    <ThemeProvider>
      <main className="flex h-screen w-screen overflow-x-hidden">
        <Tabs
          defaultValue={currentTab}
          className="!m-0 flex grow flex-col !p-0"
          onValueChange={handleTabChange}
        >
          <SiteHeader />
          <div className="relative grow">
            <TabsContent value="documents" className="absolute top-0 right-0 bottom-0 left-0">
              <DocumentManager />
            </TabsContent>
            <TabsContent value="knowledge-graph" className="absolute top-0 right-0 bottom-0 left-0">
              <GraphViewer />
            </TabsContent>
            <TabsContent value="retrieval" className="absolute top-0 right-0 bottom-0 left-0">
              <RetrievalTesting />
            </TabsContent>
            <TabsContent value="api" className="absolute top-0 right-0 bottom-0 left-0">
              <ApiSite />
            </TabsContent>
          </div>
        </Tabs>
        {enableHealthCheck && <StatusIndicator />}
        {message !== null && !apiKeyInvalid && <MessageAlert />}
        {apiKeyInvalid && <ApiKeyAlert />}
        <Toaster />
      </main>
    </ThemeProvider>
  )
}

export default App