add document manager and site heaer
clean format
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import axios, { AxiosError } from 'axios'
|
||||
import { backendBaseUrl } from '@/lib/constants'
|
||||
import { errorMessage } from '@/lib/utils'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
@@ -64,81 +65,64 @@ export type QueryResponse = {
|
||||
response: string
|
||||
}
|
||||
|
||||
export type DocumentActionResponse = {
|
||||
status: 'success' | 'partial_success' | 'failure'
|
||||
message: string
|
||||
document_count: number
|
||||
}
|
||||
|
||||
export const InvalidApiKeyError = 'Invalid API Key'
|
||||
export const RequireApiKeError = 'API Key required'
|
||||
|
||||
// Helper functions
|
||||
const getResponseContent = async (response: Response) => {
|
||||
const contentType = response.headers.get('content-type')
|
||||
if (contentType) {
|
||||
if (contentType.includes('application/json')) {
|
||||
const data = await response.json()
|
||||
return JSON.stringify(data, undefined, 2)
|
||||
} else if (contentType.startsWith('text/')) {
|
||||
return await response.text()
|
||||
} else if (contentType.includes('application/xml') || contentType.includes('text/xml')) {
|
||||
return await response.text()
|
||||
} else if (contentType.includes('application/octet-stream')) {
|
||||
const buffer = await response.arrayBuffer()
|
||||
const decoder = new TextDecoder('utf-8', { fatal: false, ignoreBOM: true })
|
||||
return decoder.decode(buffer)
|
||||
} else {
|
||||
try {
|
||||
return await response.text()
|
||||
} catch (error) {
|
||||
console.warn('Failed to decode as text, may be binary:', error)
|
||||
return `[Could not decode response body. Content-Type: ${contentType}]`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return await response.text()
|
||||
} catch (error) {
|
||||
console.warn('Failed to decode as text, may be binary:', error)
|
||||
return '[Could not decode response body. No Content-Type header.]'
|
||||
}
|
||||
// Axios instance
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: backendBaseUrl,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const fetchWithAuth = async (url: string, options: RequestInit = {}): Promise<Response> => {
|
||||
// Interceptor:add api key
|
||||
axiosInstance.interceptors.request.use((config) => {
|
||||
const apiKey = useSettingsStore.getState().apiKey
|
||||
const headers = {
|
||||
...(options.headers || {}),
|
||||
...(apiKey ? { 'X-API-Key': apiKey } : {})
|
||||
if (apiKey) {
|
||||
config.headers['X-API-Key'] = apiKey
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
const response = await fetch(backendBaseUrl + url, {
|
||||
...options,
|
||||
headers
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`${response.status} ${response.statusText}\n${await getResponseContent(response)}\n${response.url}`
|
||||
)
|
||||
// Interceptor:hanle error
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error: AxiosError) => {
|
||||
if (error.response) {
|
||||
throw new Error(
|
||||
`${error.response.status} ${error.response.statusText}\n${JSON.stringify(
|
||||
error.response.data
|
||||
)}\n${error.config?.url}`
|
||||
)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
)
|
||||
|
||||
// API methods
|
||||
export const queryGraphs = async (label: string): Promise<LightragGraphType> => {
|
||||
const response = await fetchWithAuth(`/graphs?label=${label}`)
|
||||
return await response.json()
|
||||
const response = await axiosInstance.get(`/graphs?label=${label}`)
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const getGraphLabels = async (): Promise<string[]> => {
|
||||
const response = await fetchWithAuth('/graph/label/list')
|
||||
return await response.json()
|
||||
const response = await axiosInstance.get('/graph/label/list')
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const checkHealth = async (): Promise<
|
||||
LightragStatus | { status: 'error'; message: string }
|
||||
> => {
|
||||
try {
|
||||
const response = await fetchWithAuth('/health')
|
||||
return await response.json()
|
||||
const response = await axiosInstance.get('/health')
|
||||
return response.data
|
||||
} catch (e) {
|
||||
return {
|
||||
status: 'error',
|
||||
@@ -148,63 +132,33 @@ export const checkHealth = async (): Promise<
|
||||
}
|
||||
|
||||
export const getDocuments = async (): Promise<string[]> => {
|
||||
const response = await fetchWithAuth('/documents')
|
||||
return await response.json()
|
||||
const response = await axiosInstance.get('/documents')
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const scanNewDocuments = async (): Promise<{ status: string }> => {
|
||||
const response = await axiosInstance.post('/documents/scan')
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const getDocumentsScanProgress = async (): Promise<LightragDocumentsScanProgress> => {
|
||||
const response = await fetchWithAuth('/documents/scan-progress')
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
export const uploadDocument = async (
|
||||
file: File
|
||||
): Promise<{
|
||||
status: string
|
||||
message: string
|
||||
total_documents: number
|
||||
}> => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const response = await fetchWithAuth('/documents/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
export const startDocumentScan = async (): Promise<{ status: string }> => {
|
||||
const response = await fetchWithAuth('/documents/scan', {
|
||||
method: 'POST'
|
||||
})
|
||||
return await response.json()
|
||||
const response = await axiosInstance.get('/documents/scan-progress')
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const queryText = async (request: QueryRequest): Promise<QueryResponse> => {
|
||||
const response = await fetchWithAuth('/query', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(request)
|
||||
})
|
||||
return await response.json()
|
||||
const response = await axiosInstance.post('/query', request)
|
||||
return response.data
|
||||
}
|
||||
|
||||
export const queryTextStream = async (request: QueryRequest, onChunk: (chunk: string) => void) => {
|
||||
const response = await fetchWithAuth('/query/stream', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(request)
|
||||
const response = await axiosInstance.post('/query/stream', request, {
|
||||
responseType: 'stream'
|
||||
})
|
||||
|
||||
const reader = response.body?.getReader()
|
||||
if (!reader) throw new Error('No response body')
|
||||
|
||||
const reader = response.data.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
@@ -226,53 +180,50 @@ export const queryTextStream = async (request: QueryRequest, onChunk: (chunk: st
|
||||
}
|
||||
}
|
||||
|
||||
// Text insertion API
|
||||
export const insertText = async (
|
||||
text: string,
|
||||
description?: string
|
||||
): Promise<{
|
||||
status: string
|
||||
message: string
|
||||
document_count: number
|
||||
}> => {
|
||||
const response = await fetchWithAuth('/documents/text', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ text, description })
|
||||
})
|
||||
return await response.json()
|
||||
): Promise<DocumentActionResponse> => {
|
||||
const response = await axiosInstance.post('/documents/text', { text, description })
|
||||
return response.data
|
||||
}
|
||||
|
||||
// Batch file upload API
|
||||
export const uploadBatchDocuments = async (
|
||||
files: File[]
|
||||
): Promise<{
|
||||
status: string
|
||||
message: string
|
||||
document_count: number
|
||||
}> => {
|
||||
export const uploadDocument = async (
|
||||
file: File,
|
||||
onUploadProgress?: (percentCompleted: number) => void
|
||||
): Promise<DocumentActionResponse> => {
|
||||
const formData = new FormData()
|
||||
files.forEach((file) => {
|
||||
formData.append('files', file)
|
||||
})
|
||||
formData.append('file', file)
|
||||
|
||||
const response = await fetchWithAuth('/documents/batch', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
const response = await axiosInstance.post('/documents/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress:
|
||||
onUploadProgress !== undefined
|
||||
? (progressEvent) => {
|
||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total!)
|
||||
onUploadProgress(percentCompleted)
|
||||
}
|
||||
: undefined
|
||||
})
|
||||
return await response.json()
|
||||
return response.data
|
||||
}
|
||||
|
||||
// Clear all documents API
|
||||
export const clearDocuments = async (): Promise<{
|
||||
status: string
|
||||
message: string
|
||||
document_count: number
|
||||
}> => {
|
||||
const response = await fetchWithAuth('/documents', {
|
||||
method: 'DELETE'
|
||||
})
|
||||
return await response.json()
|
||||
export const batchUploadDocuments = async (
|
||||
files: File[],
|
||||
onUploadProgress?: (fileName: string, percentCompleted: number) => void
|
||||
): Promise<DocumentActionResponse[]> => {
|
||||
return await Promise.all(
|
||||
files.map(async (file) => {
|
||||
return await uploadDocument(file, (percentCompleted) => {
|
||||
onUploadProgress?.(file.name, percentCompleted)
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export const clearDocuments = async (): Promise<DocumentActionResponse> => {
|
||||
const response = await axiosInstance.delete('/documents')
|
||||
return response.data
|
||||
}
|
||||
|
Reference in New Issue
Block a user