Merge pull request #1187 from danielaskdd/pipeline-file-path
feat: Add file name display in WebUI
This commit is contained in:
@@ -1 +1 @@
|
|||||||
__api_version__ = "1.2.5"
|
__api_version__ = "1.2.6"
|
||||||
|
@@ -91,6 +91,7 @@ class DocStatusResponse(BaseModel):
|
|||||||
chunks_count: Optional[int] = None
|
chunks_count: Optional[int] = None
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None
|
||||||
metadata: Optional[dict[str, Any]] = None
|
metadata: Optional[dict[str, Any]] = None
|
||||||
|
file_path: str
|
||||||
|
|
||||||
|
|
||||||
class DocsStatusesResponse(BaseModel):
|
class DocsStatusesResponse(BaseModel):
|
||||||
@@ -370,7 +371,7 @@ async def pipeline_enqueue_file(rag: LightRAG, file_path: Path) -> bool:
|
|||||||
|
|
||||||
# Insert into the RAG queue
|
# Insert into the RAG queue
|
||||||
if content:
|
if content:
|
||||||
await rag.apipeline_enqueue_documents(content)
|
await rag.apipeline_enqueue_documents(content, file_paths=file_path.name)
|
||||||
logger.info(f"Successfully fetched and enqueued file: {file_path.name}")
|
logger.info(f"Successfully fetched and enqueued file: {file_path.name}")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -890,6 +891,7 @@ def create_document_routes(
|
|||||||
chunks_count=doc_status.chunks_count,
|
chunks_count=doc_status.chunks_count,
|
||||||
error=doc_status.error,
|
error=doc_status.error,
|
||||||
metadata=doc_status.metadata,
|
metadata=doc_status.metadata,
|
||||||
|
file_path=doc_status.file_path,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
1
lightrag/api/webui/assets/index-BwFyYQzx.css
generated
1
lightrag/api/webui/assets/index-BwFyYQzx.css
generated
File diff suppressed because one or more lines are too long
1
lightrag/api/webui/assets/index-CR7GLPiB.css
generated
Normal file
1
lightrag/api/webui/assets/index-CR7GLPiB.css
generated
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
lightrag/api/webui/index.html
generated
4
lightrag/api/webui/index.html
generated
@@ -8,8 +8,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="logo.png" />
|
<link rel="icon" type="image/svg+xml" href="logo.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Lightrag</title>
|
<title>Lightrag</title>
|
||||||
<script type="module" crossorigin src="/webui/assets/index-DJ53id6i.js"></script>
|
<script type="module" crossorigin src="/webui/assets/index-CSLDmoSD.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/webui/assets/index-BwFyYQzx.css">
|
<link rel="stylesheet" crossorigin href="/webui/assets/index-CR7GLPiB.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@@ -124,6 +124,7 @@ export type DocStatusResponse = {
|
|||||||
chunks_count?: number
|
chunks_count?: number
|
||||||
error?: string
|
error?: string
|
||||||
metadata?: Record<string, any>
|
metadata?: Record<string, any>
|
||||||
|
file_path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DocsStatusesResponse = {
|
export type DocsStatusesResponse = {
|
||||||
|
@@ -12,7 +12,6 @@ import {
|
|||||||
} from '@/components/ui/Table'
|
} from '@/components/ui/Table'
|
||||||
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '@/components/ui/Card'
|
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '@/components/ui/Card'
|
||||||
import EmptyCard from '@/components/ui/EmptyCard'
|
import EmptyCard from '@/components/ui/EmptyCard'
|
||||||
import Text from '@/components/ui/Text'
|
|
||||||
import UploadDocumentsDialog from '@/components/documents/UploadDocumentsDialog'
|
import UploadDocumentsDialog from '@/components/documents/UploadDocumentsDialog'
|
||||||
import ClearDocumentsDialog from '@/components/documents/ClearDocumentsDialog'
|
import ClearDocumentsDialog from '@/components/documents/ClearDocumentsDialog'
|
||||||
|
|
||||||
@@ -22,12 +21,36 @@ import { toast } from 'sonner'
|
|||||||
import { useBackendState } from '@/stores/state'
|
import { useBackendState } from '@/stores/state'
|
||||||
|
|
||||||
import { RefreshCwIcon } from 'lucide-react'
|
import { RefreshCwIcon } from 'lucide-react'
|
||||||
|
import { DocStatusResponse } from '@/api/lightrag'
|
||||||
|
|
||||||
|
const getDisplayFileName = (doc: DocStatusResponse, maxLength: number = 20): string => {
|
||||||
|
// Check if file_path exists and is a non-empty string
|
||||||
|
if (!doc.file_path || typeof doc.file_path !== 'string' || doc.file_path.trim() === '') {
|
||||||
|
return doc.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to extract filename from path
|
||||||
|
const parts = doc.file_path.split('/');
|
||||||
|
const fileName = parts[parts.length - 1];
|
||||||
|
|
||||||
|
// Ensure extracted filename is valid
|
||||||
|
if (!fileName || fileName.trim() === '') {
|
||||||
|
return doc.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If filename is longer than maxLength, truncate it and add ellipsis
|
||||||
|
return fileName.length > maxLength
|
||||||
|
? fileName.slice(0, maxLength) + '...'
|
||||||
|
: fileName;
|
||||||
|
};
|
||||||
|
|
||||||
export default function DocumentManager() {
|
export default function DocumentManager() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const health = useBackendState.use.health()
|
const health = useBackendState.use.health()
|
||||||
const [docs, setDocs] = useState<DocsStatusesResponse | null>(null)
|
const [docs, setDocs] = useState<DocsStatusesResponse | null>(null)
|
||||||
const currentTab = useSettingsStore.use.currentTab()
|
const currentTab = useSettingsStore.use.currentTab()
|
||||||
|
const showFileName = useSettingsStore.use.showFileName()
|
||||||
|
const setShowFileName = useSettingsStore.use.setShowFileName()
|
||||||
|
|
||||||
const fetchDocuments = useCallback(async () => {
|
const fetchDocuments = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -107,7 +130,23 @@ export default function DocumentManager() {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
<CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
|
<CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-sm text-gray-500">{t('documentPanel.documentManager.fileNameLabel')}</span>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setShowFileName(!showFileName)}
|
||||||
|
className="border-gray-200 dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||||
|
>
|
||||||
|
{showFileName
|
||||||
|
? t('documentPanel.documentManager.hideButton')
|
||||||
|
: t('documentPanel.documentManager.showButton')
|
||||||
|
}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<CardDescription>{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
|
<CardDescription>{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
@@ -129,20 +168,45 @@ export default function DocumentManager() {
|
|||||||
<TableHead>{t('documentPanel.documentManager.columns.chunks')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.chunks')}</TableHead>
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.created')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.created')}</TableHead>
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.updated')}</TableHead>
|
<TableHead>{t('documentPanel.documentManager.columns.updated')}</TableHead>
|
||||||
<TableHead>{t('documentPanel.documentManager.columns.metadata')}</TableHead>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody className="text-sm">
|
<TableBody className="text-sm">
|
||||||
{Object.entries(docs.statuses).map(([status, documents]) =>
|
{Object.entries(docs.statuses).map(([status, documents]) =>
|
||||||
documents.map((doc) => (
|
documents.map((doc) => (
|
||||||
<TableRow key={doc.id}>
|
<TableRow key={doc.id}>
|
||||||
<TableCell className="truncate font-mono">{doc.id}</TableCell>
|
<TableCell className="truncate font-mono overflow-visible">
|
||||||
<TableCell className="max-w-xs min-w-24 truncate">
|
{showFileName ? (
|
||||||
<Text
|
<>
|
||||||
text={doc.content_summary}
|
<div className="group relative overflow-visible">
|
||||||
tooltip={doc.content_summary}
|
<div className="truncate">
|
||||||
tooltipClassName="max-w-none overflow-visible block"
|
{getDisplayFileName(doc, 35)}
|
||||||
/>
|
</div>
|
||||||
|
<div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
|
{doc.file_path}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-gray-500">{doc.id}</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="group relative overflow-visible">
|
||||||
|
<div className="truncate">
|
||||||
|
{doc.id}
|
||||||
|
</div>
|
||||||
|
<div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
|
{doc.file_path}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="max-w-xs min-w-24 truncate overflow-visible">
|
||||||
|
<div className="group relative overflow-visible">
|
||||||
|
<div className="truncate">
|
||||||
|
{doc.content_summary}
|
||||||
|
</div>
|
||||||
|
<div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
|
||||||
|
{doc.content_summary}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{status === 'processed' && (
|
{status === 'processed' && (
|
||||||
@@ -167,9 +231,6 @@ export default function DocumentManager() {
|
|||||||
<TableCell className="truncate">
|
<TableCell className="truncate">
|
||||||
{new Date(doc.updated_at).toLocaleString()}
|
{new Date(doc.updated_at).toLocaleString()}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="max-w-xs truncate">
|
|
||||||
{doc.metadata ? JSON.stringify(doc.metadata) : '-'}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
@@ -81,9 +81,14 @@
|
|||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"loadFailed": "فشل تحميل المستندات\n{{error}}",
|
"loadFailed": "فشل تحميل المستندات\n{{error}}",
|
||||||
"scanFailed": "فشل المسح الضوئي للمستندات\n{{error}}",
|
"scanFailed": "فشل مسح المستندات\n{{error}}",
|
||||||
"scanProgressFailed": "فشل الحصول على تقدم المسح الضوئي\n{{error}}"
|
"scanProgressFailed": "فشل الحصول على تقدم المسح\n{{error}}"
|
||||||
}
|
},
|
||||||
|
"fileNameLabel": "اسم الملف",
|
||||||
|
"showButton": "عرض",
|
||||||
|
"hideButton": "إخفاء",
|
||||||
|
"showFileNameTooltip": "عرض اسم الملف",
|
||||||
|
"hideFileNameTooltip": "إخفاء اسم الملف"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphPanel": {
|
"graphPanel": {
|
||||||
|
@@ -83,7 +83,12 @@
|
|||||||
"loadFailed": "Failed to load documents\n{{error}}",
|
"loadFailed": "Failed to load documents\n{{error}}",
|
||||||
"scanFailed": "Failed to scan documents\n{{error}}",
|
"scanFailed": "Failed to scan documents\n{{error}}",
|
||||||
"scanProgressFailed": "Failed to get scan progress\n{{error}}"
|
"scanProgressFailed": "Failed to get scan progress\n{{error}}"
|
||||||
}
|
},
|
||||||
|
"fileNameLabel": "File Name",
|
||||||
|
"showButton": "Show",
|
||||||
|
"hideButton": "Hide",
|
||||||
|
"showFileNameTooltip": "Show file name",
|
||||||
|
"hideFileNameTooltip": "Hide file name"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphPanel": {
|
"graphPanel": {
|
||||||
|
@@ -83,7 +83,12 @@
|
|||||||
"loadFailed": "加载文档失败\n{{error}}",
|
"loadFailed": "加载文档失败\n{{error}}",
|
||||||
"scanFailed": "扫描文档失败\n{{error}}",
|
"scanFailed": "扫描文档失败\n{{error}}",
|
||||||
"scanProgressFailed": "获取扫描进度失败\n{{error}}"
|
"scanProgressFailed": "获取扫描进度失败\n{{error}}"
|
||||||
}
|
},
|
||||||
|
"fileNameLabel": "文件名",
|
||||||
|
"showButton": "显示",
|
||||||
|
"hideButton": "隐藏",
|
||||||
|
"showFileNameTooltip": "显示文件名",
|
||||||
|
"hideFileNameTooltip": "隐藏文件名"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphPanel": {
|
"graphPanel": {
|
||||||
|
@@ -9,6 +9,10 @@ type Language = 'en' | 'zh' | 'fr' | 'ar'
|
|||||||
type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api'
|
type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api'
|
||||||
|
|
||||||
interface SettingsState {
|
interface SettingsState {
|
||||||
|
// Document manager settings
|
||||||
|
showFileName: boolean
|
||||||
|
setShowFileName: (show: boolean) => void
|
||||||
|
|
||||||
// Graph viewer settings
|
// Graph viewer settings
|
||||||
showPropertyPanel: boolean
|
showPropertyPanel: boolean
|
||||||
showNodeSearchBar: boolean
|
showNodeSearchBar: boolean
|
||||||
@@ -83,6 +87,7 @@ const useSettingsStoreBase = create<SettingsState>()(
|
|||||||
apiKey: null,
|
apiKey: null,
|
||||||
|
|
||||||
currentTab: 'documents',
|
currentTab: 'documents',
|
||||||
|
showFileName: false,
|
||||||
|
|
||||||
retrievalHistory: [],
|
retrievalHistory: [],
|
||||||
|
|
||||||
@@ -138,12 +143,14 @@ const useSettingsStoreBase = create<SettingsState>()(
|
|||||||
updateQuerySettings: (settings: Partial<QueryRequest>) =>
|
updateQuerySettings: (settings: Partial<QueryRequest>) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
querySettings: { ...state.querySettings, ...settings }
|
querySettings: { ...state.querySettings, ...settings }
|
||||||
}))
|
})),
|
||||||
|
|
||||||
|
setShowFileName: (show: boolean) => set({ showFileName: show })
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: 'settings-storage',
|
name: 'settings-storage',
|
||||||
storage: createJSONStorage(() => localStorage),
|
storage: createJSONStorage(() => localStorage),
|
||||||
version: 8,
|
version: 9,
|
||||||
migrate: (state: any, version: number) => {
|
migrate: (state: any, version: number) => {
|
||||||
if (version < 2) {
|
if (version < 2) {
|
||||||
state.showEdgeLabel = false
|
state.showEdgeLabel = false
|
||||||
@@ -186,6 +193,9 @@ const useSettingsStoreBase = create<SettingsState>()(
|
|||||||
state.graphMinDegree = 0
|
state.graphMinDegree = 0
|
||||||
state.language = 'en'
|
state.language = 'en'
|
||||||
}
|
}
|
||||||
|
if (version < 9) {
|
||||||
|
state.showFileName = false
|
||||||
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user