Merge pull request #1187 from danielaskdd/pipeline-file-path

feat: Add file name display in WebUI
This commit is contained in:
Daniel.y
2025-03-25 23:02:16 +08:00
committed by GitHub
12 changed files with 267 additions and 186 deletions

View File

@@ -1 +1 @@
__api_version__ = "1.2.5"
__api_version__ = "1.2.6"

View File

@@ -91,6 +91,7 @@ class DocStatusResponse(BaseModel):
chunks_count: Optional[int] = None
error: Optional[str] = None
metadata: Optional[dict[str, Any]] = None
file_path: str
class DocsStatusesResponse(BaseModel):
@@ -370,7 +371,7 @@ async def pipeline_enqueue_file(rag: LightRAG, file_path: Path) -> bool:
# Insert into the RAG queue
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}")
return True
else:
@@ -890,6 +891,7 @@ def create_document_routes(
chunks_count=doc_status.chunks_count,
error=doc_status.error,
metadata=doc_status.metadata,
file_path=doc_status.file_path,
)
)
return response

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="icon" type="image/svg+xml" href="logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lightrag</title>
<script type="module" crossorigin src="/webui/assets/index-DJ53id6i.js"></script>
<link rel="stylesheet" crossorigin href="/webui/assets/index-BwFyYQzx.css">
</head>
<body>
<div id="root"></div>
</body>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="icon" type="image/svg+xml" href="logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lightrag</title>
<script type="module" crossorigin src="/webui/assets/index-CSLDmoSD.js"></script>
<link rel="stylesheet" crossorigin href="/webui/assets/index-CR7GLPiB.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@@ -124,6 +124,7 @@ export type DocStatusResponse = {
chunks_count?: number
error?: string
metadata?: Record<string, any>
file_path: string
}
export type DocsStatusesResponse = {

View File

@@ -12,7 +12,6 @@ import {
} from '@/components/ui/Table'
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '@/components/ui/Card'
import EmptyCard from '@/components/ui/EmptyCard'
import Text from '@/components/ui/Text'
import UploadDocumentsDialog from '@/components/documents/UploadDocumentsDialog'
import ClearDocumentsDialog from '@/components/documents/ClearDocumentsDialog'
@@ -22,12 +21,36 @@ import { toast } from 'sonner'
import { useBackendState } from '@/stores/state'
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() {
const { t } = useTranslation()
const health = useBackendState.use.health()
const [docs, setDocs] = useState<DocsStatusesResponse | null>(null)
const currentTab = useSettingsStore.use.currentTab()
const showFileName = useSettingsStore.use.showFileName()
const setShowFileName = useSettingsStore.use.setShowFileName()
const fetchDocuments = useCallback(async () => {
try {
@@ -107,7 +130,23 @@ export default function DocumentManager() {
<Card>
<CardHeader>
<CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
<div className="flex justify-between items-center">
<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>
</CardHeader>
@@ -129,20 +168,45 @@ export default function DocumentManager() {
<TableHead>{t('documentPanel.documentManager.columns.chunks')}</TableHead>
<TableHead>{t('documentPanel.documentManager.columns.created')}</TableHead>
<TableHead>{t('documentPanel.documentManager.columns.updated')}</TableHead>
<TableHead>{t('documentPanel.documentManager.columns.metadata')}</TableHead>
</TableRow>
</TableHeader>
<TableBody className="text-sm">
{Object.entries(docs.statuses).map(([status, documents]) =>
documents.map((doc) => (
<TableRow key={doc.id}>
<TableCell className="truncate font-mono">{doc.id}</TableCell>
<TableCell className="max-w-xs min-w-24 truncate">
<Text
text={doc.content_summary}
tooltip={doc.content_summary}
tooltipClassName="max-w-none overflow-visible block"
/>
<TableCell className="truncate font-mono overflow-visible">
{showFileName ? (
<>
<div className="group relative overflow-visible">
<div className="truncate">
{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>
{status === 'processed' && (
@@ -167,9 +231,6 @@ export default function DocumentManager() {
<TableCell className="truncate">
{new Date(doc.updated_at).toLocaleString()}
</TableCell>
<TableCell className="max-w-xs truncate">
{doc.metadata ? JSON.stringify(doc.metadata) : '-'}
</TableCell>
</TableRow>
))
)}

View File

@@ -81,9 +81,14 @@
},
"errors": {
"loadFailed": "فشل تحميل المستندات\n{{error}}",
"scanFailed": "فشل المسح الضوئي للمستندات\n{{error}}",
"scanProgressFailed": "فشل الحصول على تقدم المسح الضوئي\n{{error}}"
}
"scanFailed": "فشل مسح المستندات\n{{error}}",
"scanProgressFailed": "فشل الحصول على تقدم المسح\n{{error}}"
},
"fileNameLabel": "اسم الملف",
"showButton": "عرض",
"hideButton": "إخفاء",
"showFileNameTooltip": "عرض اسم الملف",
"hideFileNameTooltip": "إخفاء اسم الملف"
}
},
"graphPanel": {

View File

@@ -83,7 +83,12 @@
"loadFailed": "Failed to load documents\n{{error}}",
"scanFailed": "Failed to scan documents\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": {

View File

@@ -83,7 +83,12 @@
"loadFailed": "加载文档失败\n{{error}}",
"scanFailed": "扫描文档失败\n{{error}}",
"scanProgressFailed": "获取扫描进度失败\n{{error}}"
}
},
"fileNameLabel": "文件名",
"showButton": "显示",
"hideButton": "隐藏",
"showFileNameTooltip": "显示文件名",
"hideFileNameTooltip": "隐藏文件名"
}
},
"graphPanel": {

View File

@@ -9,6 +9,10 @@ type Language = 'en' | 'zh' | 'fr' | 'ar'
type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api'
interface SettingsState {
// Document manager settings
showFileName: boolean
setShowFileName: (show: boolean) => void
// Graph viewer settings
showPropertyPanel: boolean
showNodeSearchBar: boolean
@@ -83,6 +87,7 @@ const useSettingsStoreBase = create<SettingsState>()(
apiKey: null,
currentTab: 'documents',
showFileName: false,
retrievalHistory: [],
@@ -138,12 +143,14 @@ const useSettingsStoreBase = create<SettingsState>()(
updateQuerySettings: (settings: Partial<QueryRequest>) =>
set((state) => ({
querySettings: { ...state.querySettings, ...settings }
}))
})),
setShowFileName: (show: boolean) => set({ showFileName: show })
}),
{
name: 'settings-storage',
storage: createJSONStorage(() => localStorage),
version: 8,
version: 9,
migrate: (state: any, version: number) => {
if (version < 2) {
state.showEdgeLabel = false
@@ -186,6 +193,9 @@ const useSettingsStoreBase = create<SettingsState>()(
state.graphMinDegree = 0
state.language = 'en'
}
if (version < 9) {
state.showFileName = false
}
return state
}
}