upgraded datra management ui

This commit is contained in:
Saifeddine ALOUI 2025-02-02 10:54:57 +01:00
parent 53d8530ace
commit afd2096d15
5 changed files with 334 additions and 137 deletions

17
web/dist/assets/index-BkRL-g00.css vendored Normal file

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

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script> <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI</title> <title>LoLLMS WebUI</title>
<script type="module" crossorigin src="/assets/index-B_kgz78p.js"></script> <script type="module" crossorigin src="/assets/index-CsOg18Ru.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-zuZ7rDcs.css"> <link rel="stylesheet" crossorigin href="/assets/index-BkRL-g00.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@ -1358,7 +1358,44 @@
</div> </div>
</div> </div>
<div class="flex items-center" :key="index">
<div class="relative mr-2">
<button
@click="toggleStatus(index)"
class="flex items-center space-x-1"
>
<div
:class="[
'w-3 h-3 rounded-full',
getStatusColor(index)
]"
></div>
<div
v-if="expandedStatusIndex === index"
class="absolute left-5 top-0 bg-white shadow-lg rounded-md p-2 z-10 text-sm"
>
<div v-if="serverStatuses[index]">
<p>Status: {{ serverStatuses[index].status }}</p>
<p>Indexed Files: {{ serverStatuses[index].indexed_files_count }}</p>
<p>Model: {{ serverStatuses[index].configuration?.llm_model }}</p>
</div>
<p v-else>No status available</p>
</div>
</button>
</div>
<button
v-if="source.type === 'lightrag'"
@click="checkLightRagServerHealth(index)"
class="inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
title="Check LightRAG server health"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
LightRAG Status
</button>
</div>
<!-- Actions Row --> <!-- Actions Row -->
<div class="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700"> <div class="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
<div class="flex items-center space-x-4"> <div class="flex items-center space-x-4">
@ -1404,7 +1441,7 @@
</svg> </svg>
Select work Folder Select work Folder
</button> </button>
<!-- Health Check Button for LightRAG -->
<button @click="removeServedDataBase(index)" <button @click="removeServedDataBase(index)"
class="inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-500"> class="inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -4365,7 +4402,14 @@
</div> </div>
</div> </div>
<div v-if="settingsChanged" <div v-if="settingsChanged"
class="fixed bottom-4 right-4 z-50 bg-white dark:bg-gray-800 shadow-lg rounded-lg p-4 flex gap-3 items-center border border-gray-200 dark:border-gray-700"> class="fixed bottom-4 right-4 z-50 bg-white dark:bg-gray-800 shadow-lg rounded-lg p-4 flex flex-col gap-2 border border-gray-200 dark:border-gray-700">
<!-- Status Message -->
<div class="flex items-center gap-2 text-amber-600 dark:text-amber-400">
<i data-feather="alert-circle" class="w-4 h-4"></i>
<span class="text-sm font-medium">Settings have been modified</span>
</div>
<!-- Action Buttons -->
<div v-if="!isLoading" class="flex items-center gap-2"> <div v-if="!isLoading" class="flex items-center gap-2">
<button class="flex items-center gap-2 px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 duration-75 active:scale-95" <button class="flex items-center gap-2 px-3 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 duration-75 active:scale-95"
title="Apply changes" title="Apply changes"
@ -4539,10 +4583,13 @@ export default {
data() { data() {
return { return {
posts_headers : { posts_headers : {
'accept': 'application/json', 'accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
serverStatuses: {}, // Object to store status for each server
expandedStatusIndex: null, // Track which status panel is expanded
isUploading: false, isUploading: false,
defaultModelImgPlaceholder:defaultModelImgPlaceholder, defaultModelImgPlaceholder:defaultModelImgPlaceholder,
snd_input_devices: [], snd_input_devices: [],
@ -4669,43 +4716,185 @@ export default {
//await socket.on('install_progress', this.progressListener); //await socket.on('install_progress', this.progressListener);
}, },
methods: { methods: {
triggerFileInput() { async checkLightRagServerHealth(index) {
this.$refs.fileInput.click() try {
const source = this.configFile.datalakes[index];
const headers = source.key ? { 'X-API-Key': source.key } : {};
const response = await fetch(`${source.url.replace(/\/+$/, '')}/health`, { headers });
const data = await response.json();
// Update status for this specific server
this.serverStatuses[index]= {
status: 'healthy',
indexed_files_count: data.indexed_files_count,
configuration: data.configuration
};
this.$store.state.toast.showToast(
`Healthy | ${data.indexed_files_count} files indexed | Model: ${data.configuration.llm_model}`,
4,
true
);
return data;
} catch (error) {
// Update status for this specific server on error
this.serverStatuses[index]= {
status: 'unhealthy'
};
this.$store.state.toast.showToast('Could not connect to LightRAG server', 4, false);
}
}, },
async handleFileUpload(event) {
const files = event.target.files
if (!files.length) return
this.isUploading = true // Optional: Method to check all servers at once
const formData = new FormData() async checkAllServers() {
for (let i = 0; i < this.configFile.datalakes.length; i++) {
if (this.configFile.datalakes[i].type === 'lightrag') {
await this.checkLightRagServerHealth(i);
}
}
},
// Add database name async uploadFilesToLightRag(index, files) {
formData.append('database_name', this.databaseName) const source = this.configFile.datalakes[index];
const headers = source.key ? { 'X-API-Key': source.key } : {};
// Add all files for (const file of files) {
Array.from(files).forEach(file => { const formData = new FormData();
formData.append('files', file) formData.append('file', file);
})
try { try {
const response = await axios.post('/upload_files_2_rag_db', formData, { const response = await fetch(`${source.url}/documents/upload`, {
headers: { method: 'POST',
'Content-Type': 'multipart/form-data' headers,
}, body: formData
onUploadProgress: (progressEvent) => { });
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
this.$emit('upload-progress', percentCompleted)
}
})
this.$emit('upload-success', response.data) const result = await response.json();
this.$emit('show-notification', {
title: 'LightRAG Upload Success',
message: `${file.name} uploaded successfully`,
type: 'success'
});
} catch (error) { } catch (error) {
console.error('Upload failed:', error) this.$emit('show-notification', {
this.$emit('upload-error', error) title: 'LightRAG Upload Error',
} finally { message: `Failed to upload ${file.name}: ${error.message}`,
this.isUploading = false type: 'error'
event.target.value = '' });
} }
}
},
async handleFileUpload(event, index) {
const files = Array.from(event.target.files);
const source = this.configFile.datalakes[index];
const supportedExtensions = {
lightrag: ['.txt', '.md', '.pdf', '.docx', '.pptx', '.xlsx'],
lollmsvectordb: [".sh",
".json",
".sym",
".log",
".snippet",
".se",
".yml",
".snippets",
".lua",
".pdf",
".md",
".docx",
".xlsx",
".png",
".bmp",
".jpg",
".yaml",
".inc",
".txt",
".ini",
".pas",
".pptx",
".map",
".php",
".xlsx",
".rtf",
".hpp",
".h",
".asm",
".xml",
".hh",
".sql",
".java",
".c",
".html",
".inf",
".rb",
".py",
".cs",
".js",
".bat",
".css",
".s",
".cpp",
".csv",
".msg"
]
};
const validFiles = files.filter(file => {
const ext = '.' + file.name.split('.').pop().toLowerCase();
return supportedExtensions[source.type].includes(ext);
});
if (validFiles.length !== files.length) {
this.$emit('show-notification', {
title: 'Warning',
message: 'Some files were skipped due to unsupported format',
type: 'warning'
});
}
if (source.type === 'lightrag') {
await this.uploadFilesToLightRag(index, validFiles);
} else {
try {
if (!files.length) return
this.isUploading = true
const formData = new FormData()
// Add database name
formData.append('database_name', this.databaseName)
// Add all files
Array.from(files).forEach(file => {
formData.append('files', file)
})
const response = await axios.post('/upload_files_2_rag_db', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
this.$emit('upload-progress', percentCompleted)
}
})
this.$emit('upload-success', response.data)
} catch (error) {
console.error('Upload failed:', error)
this.$emit('upload-error', error)
} finally {
this.isUploading = false
event.target.value = ''
}
}
},
triggerFileInput() {
this.$refs.fileInput.click()
}, },
updateRagDatabase(index, value, field) { updateRagDatabase(index, value, field) {
if (field) { if (field) {
@ -6953,6 +7142,14 @@ export default {
//this.load_everything() //this.load_everything()
}, },
computed: { computed: {
getStatusColor() {
return (index) => {
const status = this.serverStatuses[index]
if (!status) return 'bg-gray-400' // Unknown status
if (status.status === 'healthy') return 'bg-green-500' // Healthy
return 'bg-red-500' // Unhealthy
}
},
full_template:{ full_template:{
get(){ get(){
return (this.configFile.start_header_id_template+this.configFile.system_message_template+this.configFile.end_header_id_template+" system message"+this.configFile.separator_template+this.configFile.start_user_header_id_template+"user name"+this.configFile.end_user_header_id_template+" User prompt"+this.configFile.separator_template+this.configFile.end_user_message_id_template+this.configFile.separator_template+this.configFile.start_ai_header_id_template+"ai personality"+this.configFile.end_ai_header_id_template+"ai response"+this.configFile.end_ai_message_id_template).replace("\n","<br>") return (this.configFile.start_header_id_template+this.configFile.system_message_template+this.configFile.end_header_id_template+" system message"+this.configFile.separator_template+this.configFile.start_user_header_id_template+"user name"+this.configFile.end_user_header_id_template+" User prompt"+this.configFile.separator_template+this.configFile.end_user_message_id_template+this.configFile.separator_template+this.configFile.start_ai_header_id_template+"ai personality"+this.configFile.end_ai_header_id_template+"ai response"+this.configFile.end_ai_message_id_template).replace("\n","<br>")