yangdx
commited on
Commit
·
98c48d2
1
Parent(s):
87e5ea7
Add title support for webui
Browse files
env.example
CHANGED
@@ -5,8 +5,8 @@
|
|
5 |
# PORT=9621
|
6 |
# WORKERS=2
|
7 |
# CORS_ORIGINS=http://localhost:3000,http://localhost:8080
|
8 |
-
|
9 |
-
|
10 |
|
11 |
### Optional SSL Configuration
|
12 |
# SSL=true
|
|
|
5 |
# PORT=9621
|
6 |
# WORKERS=2
|
7 |
# CORS_ORIGINS=http://localhost:3000,http://localhost:8080
|
8 |
+
WEBUI_TITLE='Graph RAG Engine'
|
9 |
+
WEBUI_DESCRIPTION="Simple and Fast Graph Based RAG System"
|
10 |
|
11 |
### Optional SSL Configuration
|
12 |
# SSL=true
|
lightrag_webui/src/api/lightrag.ts
CHANGED
@@ -3,6 +3,7 @@ import { backendBaseUrl } from '@/lib/constants'
|
|
3 |
import { errorMessage } from '@/lib/utils'
|
4 |
import { useSettingsStore } from '@/stores/settings'
|
5 |
import { navigationService } from '@/services/navigation'
|
|
|
6 |
|
7 |
// Types
|
8 |
export type LightragNodeType = {
|
@@ -46,6 +47,8 @@ export type LightragStatus = {
|
|
46 |
api_version?: string
|
47 |
auth_mode?: 'enabled' | 'disabled'
|
48 |
pipeline_busy: boolean
|
|
|
|
|
49 |
}
|
50 |
|
51 |
export type LightragDocumentsScanProgress = {
|
@@ -140,6 +143,8 @@ export type AuthStatusResponse = {
|
|
140 |
message?: string
|
141 |
core_version?: string
|
142 |
api_version?: string
|
|
|
|
|
143 |
}
|
144 |
|
145 |
export type PipelineStatusResponse = {
|
@@ -163,6 +168,8 @@ export type LoginResponse = {
|
|
163 |
message?: string // Optional message
|
164 |
core_version?: string
|
165 |
api_version?: string
|
|
|
|
|
166 |
}
|
167 |
|
168 |
export const InvalidApiKeyError = 'Invalid API Key'
|
@@ -419,12 +426,26 @@ export const getAuthStatus = async (): Promise<AuthStatusResponse> => {
|
|
419 |
// For unconfigured auth, ensure we have an access token
|
420 |
if (!response.data.auth_configured) {
|
421 |
if (response.data.access_token && typeof response.data.access_token === 'string') {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
422 |
return response.data;
|
423 |
} else {
|
424 |
console.warn('Auth not configured but no valid access token provided');
|
425 |
}
|
426 |
} else {
|
427 |
// For configured auth, just return the data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
return response.data;
|
429 |
}
|
430 |
}
|
@@ -463,5 +484,13 @@ export const loginToServer = async (username: string, password: string): Promise
|
|
463 |
}
|
464 |
});
|
465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
return response.data;
|
467 |
}
|
|
|
3 |
import { errorMessage } from '@/lib/utils'
|
4 |
import { useSettingsStore } from '@/stores/settings'
|
5 |
import { navigationService } from '@/services/navigation'
|
6 |
+
import { useAuthStore } from '@/stores/state'
|
7 |
|
8 |
// Types
|
9 |
export type LightragNodeType = {
|
|
|
47 |
api_version?: string
|
48 |
auth_mode?: 'enabled' | 'disabled'
|
49 |
pipeline_busy: boolean
|
50 |
+
webui_title?: string
|
51 |
+
webui_description?: string
|
52 |
}
|
53 |
|
54 |
export type LightragDocumentsScanProgress = {
|
|
|
143 |
message?: string
|
144 |
core_version?: string
|
145 |
api_version?: string
|
146 |
+
webui_title?: string
|
147 |
+
webui_description?: string
|
148 |
}
|
149 |
|
150 |
export type PipelineStatusResponse = {
|
|
|
168 |
message?: string // Optional message
|
169 |
core_version?: string
|
170 |
api_version?: string
|
171 |
+
webui_title?: string
|
172 |
+
webui_description?: string
|
173 |
}
|
174 |
|
175 |
export const InvalidApiKeyError = 'Invalid API Key'
|
|
|
426 |
// For unconfigured auth, ensure we have an access token
|
427 |
if (!response.data.auth_configured) {
|
428 |
if (response.data.access_token && typeof response.data.access_token === 'string') {
|
429 |
+
// Update custom title if available
|
430 |
+
if (response.data.webui_title || response.data.webui_description) {
|
431 |
+
useAuthStore.getState().setCustomTitle(
|
432 |
+
response.data.webui_title || null,
|
433 |
+
response.data.webui_description || null
|
434 |
+
);
|
435 |
+
}
|
436 |
return response.data;
|
437 |
} else {
|
438 |
console.warn('Auth not configured but no valid access token provided');
|
439 |
}
|
440 |
} else {
|
441 |
// For configured auth, just return the data
|
442 |
+
// Update custom title if available
|
443 |
+
if (response.data.webui_title || response.data.webui_description) {
|
444 |
+
useAuthStore.getState().setCustomTitle(
|
445 |
+
response.data.webui_title || null,
|
446 |
+
response.data.webui_description || null
|
447 |
+
);
|
448 |
+
}
|
449 |
return response.data;
|
450 |
}
|
451 |
}
|
|
|
484 |
}
|
485 |
});
|
486 |
|
487 |
+
// Update custom title if available
|
488 |
+
if (response.data.webui_title || response.data.webui_description) {
|
489 |
+
useAuthStore.getState().setCustomTitle(
|
490 |
+
response.data.webui_title || null,
|
491 |
+
response.data.webui_description || null
|
492 |
+
);
|
493 |
+
}
|
494 |
+
|
495 |
return response.data;
|
496 |
}
|
lightrag_webui/src/features/SiteHeader.tsx
CHANGED
@@ -8,6 +8,7 @@ import { cn } from '@/lib/utils'
|
|
8 |
import { useTranslation } from 'react-i18next'
|
9 |
import { navigationService } from '@/services/navigation'
|
10 |
import { ZapIcon, GithubIcon, LogOutIcon } from 'lucide-react'
|
|
|
11 |
|
12 |
interface NavigationTabProps {
|
13 |
value: string
|
@@ -55,7 +56,7 @@ function TabsNavigation() {
|
|
55 |
|
56 |
export default function SiteHeader() {
|
57 |
const { t } = useTranslation()
|
58 |
-
const { isGuestMode, coreVersion, apiVersion, username } = useAuthStore()
|
59 |
|
60 |
const versionDisplay = (coreVersion && apiVersion)
|
61 |
? `${coreVersion}/${apiVersion}`
|
@@ -67,17 +68,31 @@ export default function SiteHeader() {
|
|
67 |
|
68 |
return (
|
69 |
<header className="border-border/40 bg-background/95 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-50 flex h-10 w-full border-b px-4 backdrop-blur">
|
70 |
-
<div className="w-[200px] flex items-center">
|
71 |
<a href={webuiPrefix} className="flex items-center gap-2">
|
72 |
<ZapIcon className="size-4 text-emerald-400" aria-hidden="true" />
|
73 |
{/* <img src='/logo.png' className="size-4" /> */}
|
74 |
<span className="font-bold md:inline-block">{SiteInfo.name}</span>
|
75 |
-
{versionDisplay && (
|
76 |
-
<span className="ml-2 text-xs text-gray-500 dark:text-gray-400">
|
77 |
-
v{versionDisplay}
|
78 |
-
</span>
|
79 |
-
)}
|
80 |
</a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
</div>
|
82 |
|
83 |
<div className="flex h-10 flex-1 items-center justify-center">
|
@@ -91,6 +106,11 @@ export default function SiteHeader() {
|
|
91 |
|
92 |
<nav className="w-[200px] flex items-center justify-end">
|
93 |
<div className="flex items-center gap-2">
|
|
|
|
|
|
|
|
|
|
|
94 |
<Button variant="ghost" size="icon" side="bottom" tooltip={t('header.projectRepository')}>
|
95 |
<a href={SiteInfo.github} target="_blank" rel="noopener noreferrer">
|
96 |
<GithubIcon className="size-4" aria-hidden="true" />
|
|
|
8 |
import { useTranslation } from 'react-i18next'
|
9 |
import { navigationService } from '@/services/navigation'
|
10 |
import { ZapIcon, GithubIcon, LogOutIcon } from 'lucide-react'
|
11 |
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/Tooltip'
|
12 |
|
13 |
interface NavigationTabProps {
|
14 |
value: string
|
|
|
56 |
|
57 |
export default function SiteHeader() {
|
58 |
const { t } = useTranslation()
|
59 |
+
const { isGuestMode, coreVersion, apiVersion, username, webuiTitle, webuiDescription } = useAuthStore()
|
60 |
|
61 |
const versionDisplay = (coreVersion && apiVersion)
|
62 |
? `${coreVersion}/${apiVersion}`
|
|
|
68 |
|
69 |
return (
|
70 |
<header className="border-border/40 bg-background/95 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-50 flex h-10 w-full border-b px-4 backdrop-blur">
|
71 |
+
<div className="min-w-[200px] w-auto flex items-center">
|
72 |
<a href={webuiPrefix} className="flex items-center gap-2">
|
73 |
<ZapIcon className="size-4 text-emerald-400" aria-hidden="true" />
|
74 |
{/* <img src='/logo.png' className="size-4" /> */}
|
75 |
<span className="font-bold md:inline-block">{SiteInfo.name}</span>
|
|
|
|
|
|
|
|
|
|
|
76 |
</a>
|
77 |
+
{webuiTitle && (
|
78 |
+
<div className="flex items-center">
|
79 |
+
<span className="mx-1 text-xs text-gray-500 dark:text-gray-400">|</span>
|
80 |
+
<TooltipProvider>
|
81 |
+
<Tooltip>
|
82 |
+
<TooltipTrigger asChild>
|
83 |
+
<span className="font-medium text-sm cursor-default">
|
84 |
+
{webuiTitle}
|
85 |
+
</span>
|
86 |
+
</TooltipTrigger>
|
87 |
+
{webuiDescription && (
|
88 |
+
<TooltipContent side="bottom">
|
89 |
+
{webuiDescription}
|
90 |
+
</TooltipContent>
|
91 |
+
)}
|
92 |
+
</Tooltip>
|
93 |
+
</TooltipProvider>
|
94 |
+
</div>
|
95 |
+
)}
|
96 |
</div>
|
97 |
|
98 |
<div className="flex h-10 flex-1 items-center justify-center">
|
|
|
106 |
|
107 |
<nav className="w-[200px] flex items-center justify-end">
|
108 |
<div className="flex items-center gap-2">
|
109 |
+
{versionDisplay && (
|
110 |
+
<span className="text-xs text-gray-500 dark:text-gray-400 mr-1">
|
111 |
+
v{versionDisplay}
|
112 |
+
</span>
|
113 |
+
)}
|
114 |
<Button variant="ghost" size="icon" side="bottom" tooltip={t('header.projectRepository')}>
|
115 |
<a href={SiteInfo.github} target="_blank" rel="noopener noreferrer">
|
116 |
<GithubIcon className="size-4" aria-hidden="true" />
|
lightrag_webui/src/stores/state.ts
CHANGED
@@ -22,10 +22,13 @@ interface AuthState {
|
|
22 |
coreVersion: string | null;
|
23 |
apiVersion: string | null;
|
24 |
username: string | null; // login username
|
|
|
|
|
25 |
|
26 |
-
login: (token: string, isGuest?: boolean, coreVersion?: string | null, apiVersion?: string | null) => void;
|
27 |
logout: () => void;
|
28 |
setVersion: (coreVersion: string | null, apiVersion: string | null) => void;
|
|
|
29 |
}
|
30 |
|
31 |
const useBackendStateStoreBase = create<BackendState>()((set) => ({
|
@@ -46,6 +49,14 @@ const useBackendStateStoreBase = create<BackendState>()((set) => ({
|
|
46 |
health.api_version || null
|
47 |
);
|
48 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
set({
|
51 |
health: true,
|
@@ -107,10 +118,12 @@ const isGuestToken = (token: string): boolean => {
|
|
107 |
return payload.role === 'guest';
|
108 |
};
|
109 |
|
110 |
-
const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; coreVersion: string | null; apiVersion: string | null; username: string | null } => {
|
111 |
const token = localStorage.getItem('LIGHTRAG-API-TOKEN');
|
112 |
const coreVersion = localStorage.getItem('LIGHTRAG-CORE-VERSION');
|
113 |
const apiVersion = localStorage.getItem('LIGHTRAG-API-VERSION');
|
|
|
|
|
114 |
const username = token ? getUsernameFromToken(token) : null;
|
115 |
|
116 |
if (!token) {
|
@@ -120,6 +133,8 @@ const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; core
|
|
120 |
coreVersion: coreVersion,
|
121 |
apiVersion: apiVersion,
|
122 |
username: null,
|
|
|
|
|
123 |
};
|
124 |
}
|
125 |
|
@@ -129,6 +144,8 @@ const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; core
|
|
129 |
coreVersion: coreVersion,
|
130 |
apiVersion: apiVersion,
|
131 |
username: username,
|
|
|
|
|
132 |
};
|
133 |
};
|
134 |
|
@@ -142,8 +159,10 @@ export const useAuthStore = create<AuthState>(set => {
|
|
142 |
coreVersion: initialState.coreVersion,
|
143 |
apiVersion: initialState.apiVersion,
|
144 |
username: initialState.username,
|
|
|
|
|
145 |
|
146 |
-
login: (token, isGuest = false, coreVersion = null, apiVersion = null) => {
|
147 |
localStorage.setItem('LIGHTRAG-API-TOKEN', token);
|
148 |
|
149 |
if (coreVersion) {
|
@@ -152,6 +171,12 @@ export const useAuthStore = create<AuthState>(set => {
|
|
152 |
if (apiVersion) {
|
153 |
localStorage.setItem('LIGHTRAG-API-VERSION', apiVersion);
|
154 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
|
156 |
const username = getUsernameFromToken(token);
|
157 |
set({
|
@@ -160,6 +185,8 @@ export const useAuthStore = create<AuthState>(set => {
|
|
160 |
username: username,
|
161 |
coreVersion: coreVersion,
|
162 |
apiVersion: apiVersion,
|
|
|
|
|
163 |
});
|
164 |
},
|
165 |
|
@@ -168,6 +195,8 @@ export const useAuthStore = create<AuthState>(set => {
|
|
168 |
|
169 |
const coreVersion = localStorage.getItem('LIGHTRAG-CORE-VERSION');
|
170 |
const apiVersion = localStorage.getItem('LIGHTRAG-API-VERSION');
|
|
|
|
|
171 |
|
172 |
set({
|
173 |
isAuthenticated: false,
|
@@ -175,6 +204,8 @@ export const useAuthStore = create<AuthState>(set => {
|
|
175 |
username: null,
|
176 |
coreVersion: coreVersion,
|
177 |
apiVersion: apiVersion,
|
|
|
|
|
178 |
});
|
179 |
},
|
180 |
|
@@ -192,6 +223,27 @@ export const useAuthStore = create<AuthState>(set => {
|
|
192 |
coreVersion: coreVersion,
|
193 |
apiVersion: apiVersion
|
194 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
}
|
196 |
};
|
197 |
});
|
|
|
22 |
coreVersion: string | null;
|
23 |
apiVersion: string | null;
|
24 |
username: string | null; // login username
|
25 |
+
webuiTitle: string | null; // Custom title
|
26 |
+
webuiDescription: string | null; // Title description
|
27 |
|
28 |
+
login: (token: string, isGuest?: boolean, coreVersion?: string | null, apiVersion?: string | null, webuiTitle?: string | null, webuiDescription?: string | null) => void;
|
29 |
logout: () => void;
|
30 |
setVersion: (coreVersion: string | null, apiVersion: string | null) => void;
|
31 |
+
setCustomTitle: (webuiTitle: string | null, webuiDescription: string | null) => void;
|
32 |
}
|
33 |
|
34 |
const useBackendStateStoreBase = create<BackendState>()((set) => ({
|
|
|
49 |
health.api_version || null
|
50 |
);
|
51 |
}
|
52 |
+
|
53 |
+
// Update custom title information if health check returns it
|
54 |
+
if (health.webui_title || health.webui_description) {
|
55 |
+
useAuthStore.getState().setCustomTitle(
|
56 |
+
health.webui_title || null,
|
57 |
+
health.webui_description || null
|
58 |
+
);
|
59 |
+
}
|
60 |
|
61 |
set({
|
62 |
health: true,
|
|
|
118 |
return payload.role === 'guest';
|
119 |
};
|
120 |
|
121 |
+
const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; coreVersion: string | null; apiVersion: string | null; username: string | null; webuiTitle: string | null; webuiDescription: string | null } => {
|
122 |
const token = localStorage.getItem('LIGHTRAG-API-TOKEN');
|
123 |
const coreVersion = localStorage.getItem('LIGHTRAG-CORE-VERSION');
|
124 |
const apiVersion = localStorage.getItem('LIGHTRAG-API-VERSION');
|
125 |
+
const webuiTitle = localStorage.getItem('LIGHTRAG-WEBUI-TITLE');
|
126 |
+
const webuiDescription = localStorage.getItem('LIGHTRAG-WEBUI-DESCRIPTION');
|
127 |
const username = token ? getUsernameFromToken(token) : null;
|
128 |
|
129 |
if (!token) {
|
|
|
133 |
coreVersion: coreVersion,
|
134 |
apiVersion: apiVersion,
|
135 |
username: null,
|
136 |
+
webuiTitle: webuiTitle,
|
137 |
+
webuiDescription: webuiDescription,
|
138 |
};
|
139 |
}
|
140 |
|
|
|
144 |
coreVersion: coreVersion,
|
145 |
apiVersion: apiVersion,
|
146 |
username: username,
|
147 |
+
webuiTitle: webuiTitle,
|
148 |
+
webuiDescription: webuiDescription,
|
149 |
};
|
150 |
};
|
151 |
|
|
|
159 |
coreVersion: initialState.coreVersion,
|
160 |
apiVersion: initialState.apiVersion,
|
161 |
username: initialState.username,
|
162 |
+
webuiTitle: initialState.webuiTitle,
|
163 |
+
webuiDescription: initialState.webuiDescription,
|
164 |
|
165 |
+
login: (token, isGuest = false, coreVersion = null, apiVersion = null, webuiTitle = null, webuiDescription = null) => {
|
166 |
localStorage.setItem('LIGHTRAG-API-TOKEN', token);
|
167 |
|
168 |
if (coreVersion) {
|
|
|
171 |
if (apiVersion) {
|
172 |
localStorage.setItem('LIGHTRAG-API-VERSION', apiVersion);
|
173 |
}
|
174 |
+
if (webuiTitle) {
|
175 |
+
localStorage.setItem('LIGHTRAG-WEBUI-TITLE', webuiTitle);
|
176 |
+
}
|
177 |
+
if (webuiDescription) {
|
178 |
+
localStorage.setItem('LIGHTRAG-WEBUI-DESCRIPTION', webuiDescription);
|
179 |
+
}
|
180 |
|
181 |
const username = getUsernameFromToken(token);
|
182 |
set({
|
|
|
185 |
username: username,
|
186 |
coreVersion: coreVersion,
|
187 |
apiVersion: apiVersion,
|
188 |
+
webuiTitle: webuiTitle,
|
189 |
+
webuiDescription: webuiDescription,
|
190 |
});
|
191 |
},
|
192 |
|
|
|
195 |
|
196 |
const coreVersion = localStorage.getItem('LIGHTRAG-CORE-VERSION');
|
197 |
const apiVersion = localStorage.getItem('LIGHTRAG-API-VERSION');
|
198 |
+
const webuiTitle = localStorage.getItem('LIGHTRAG-WEBUI-TITLE');
|
199 |
+
const webuiDescription = localStorage.getItem('LIGHTRAG-WEBUI-DESCRIPTION');
|
200 |
|
201 |
set({
|
202 |
isAuthenticated: false,
|
|
|
204 |
username: null,
|
205 |
coreVersion: coreVersion,
|
206 |
apiVersion: apiVersion,
|
207 |
+
webuiTitle: webuiTitle,
|
208 |
+
webuiDescription: webuiDescription,
|
209 |
});
|
210 |
},
|
211 |
|
|
|
223 |
coreVersion: coreVersion,
|
224 |
apiVersion: apiVersion
|
225 |
});
|
226 |
+
},
|
227 |
+
|
228 |
+
setCustomTitle: (webuiTitle, webuiDescription) => {
|
229 |
+
// Update localStorage
|
230 |
+
if (webuiTitle) {
|
231 |
+
localStorage.setItem('LIGHTRAG-WEBUI-TITLE', webuiTitle);
|
232 |
+
} else {
|
233 |
+
localStorage.removeItem('LIGHTRAG-WEBUI-TITLE');
|
234 |
+
}
|
235 |
+
|
236 |
+
if (webuiDescription) {
|
237 |
+
localStorage.setItem('LIGHTRAG-WEBUI-DESCRIPTION', webuiDescription);
|
238 |
+
} else {
|
239 |
+
localStorage.removeItem('LIGHTRAG-WEBUI-DESCRIPTION');
|
240 |
+
}
|
241 |
+
|
242 |
+
// Update state
|
243 |
+
set({
|
244 |
+
webuiTitle: webuiTitle,
|
245 |
+
webuiDescription: webuiDescription
|
246 |
+
});
|
247 |
}
|
248 |
};
|
249 |
});
|