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
- # WEBUI_TITLE='My Best RAG System'
9
- # WEBUI_DESCRIPTION="My Knowledge System Based on LightRAG"
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
  });