add redis backend
This commit is contained in:
@@ -324,22 +324,22 @@ export function Dashboard({ onProcessingChange }: DashboardProps = {}) {
|
||||
</div>
|
||||
<Tabs defaultValue="files" className="flex flex-col flex-1">
|
||||
<div className="border-b border-gray-200 px-6 py-2">
|
||||
<TabsList className="flex h-10 items-center gap-2 bg-transparent p-0 justify-start">
|
||||
<TabsList className="flex h-10 w-full items-center gap-2 bg-transparent p-0 justify-start">
|
||||
<TabsTrigger
|
||||
value="dashboard"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-black data-[state=active]:text-white data-[state=active]:shadow-lg data-[state=active]:ring-0 data-[state=active]:shadow-black/30"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-gray-900 data-[state=active]:text-white data-[state=active]:shadow"
|
||||
>
|
||||
Dashboard
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="files"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-black data-[state=active]:text-white data-[state=active]:shadow-lg data-[state=active]:ring-0 data-[state=active]:shadow-black/30"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-gray-900 data-[state=active]:text-white data-[state=active]:shadow"
|
||||
>
|
||||
Files
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="chat"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-black data-[state=active]:text-white data-[state=active]:shadow-lg data-[state=active]:ring-0 data-[state=active]:shadow-black/30"
|
||||
className="rounded-md px-4 py-2 text-sm font-medium text-gray-600 transition data-[state=active]:bg-gray-900 data-[state=active]:text-white data-[state=active]:shadow"
|
||||
>
|
||||
Chat
|
||||
</TabsTrigger>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
RefreshCcw,
|
||||
Plus,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
@@ -18,6 +19,16 @@ import {
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
interface SidebarProps {
|
||||
onNavigateToSchemas?: () => void;
|
||||
@@ -42,6 +53,10 @@ export function Sidebar({
|
||||
} = useFileStore();
|
||||
|
||||
const [deletingTema, setDeletingTema] = useState<string | null>(null);
|
||||
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
||||
const [newDataroomName, setNewDataroomName] = useState("");
|
||||
const [creatingDataroom, setCreatingDataroom] = useState(false);
|
||||
const [createError, setCreateError] = useState<string | null>(null);
|
||||
|
||||
const renderWithTooltip = (label: string, element: ReactElement) => {
|
||||
if (!collapsed) {
|
||||
@@ -58,6 +73,51 @@ export function Sidebar({
|
||||
);
|
||||
};
|
||||
|
||||
const handleCreateDialogOpenChange = (open: boolean) => {
|
||||
setCreateDialogOpen(open);
|
||||
if (!open) {
|
||||
setNewDataroomName("");
|
||||
setCreateError(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateDataroom = async () => {
|
||||
const trimmed = newDataroomName.trim();
|
||||
if (!trimmed) {
|
||||
setCreateError("El nombre es obligatorio");
|
||||
return;
|
||||
}
|
||||
|
||||
setCreatingDataroom(true);
|
||||
setCreateError(null);
|
||||
|
||||
try {
|
||||
console.log("Creating dataroom:", trimmed);
|
||||
const result = await api.createDataroom({ name: trimmed });
|
||||
console.log("Dataroom created successfully:", result);
|
||||
|
||||
// Refresh the datarooms list (this will load all datarooms including the new one)
|
||||
console.log("Refreshing dataroom list...");
|
||||
await loadTemas();
|
||||
console.log("Dataroom list refreshed");
|
||||
|
||||
// Select the newly created dataroom
|
||||
setSelectedTema(trimmed);
|
||||
|
||||
// Close dialog and show success
|
||||
handleCreateDialogOpenChange(false);
|
||||
} catch (error) {
|
||||
console.error("Error creating dataroom:", error);
|
||||
setCreateError(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "No se pudo crear el dataroom. Inténtalo nuevamente.",
|
||||
);
|
||||
} finally {
|
||||
setCreatingDataroom(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadTemas();
|
||||
}, []);
|
||||
@@ -65,10 +125,35 @@ export function Sidebar({
|
||||
const loadTemas = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await api.getTemas();
|
||||
setTemas(response.temas);
|
||||
const response = await api.getDatarooms();
|
||||
console.log("Raw datarooms response:", response);
|
||||
|
||||
// Extract dataroom names from the response with better error handling
|
||||
let dataroomNames: string[] = [];
|
||||
if (response && response.datarooms && Array.isArray(response.datarooms)) {
|
||||
dataroomNames = response.datarooms
|
||||
.filter((dataroom) => dataroom && dataroom.name)
|
||||
.map((dataroom) => dataroom.name);
|
||||
}
|
||||
|
||||
setTemas(dataroomNames);
|
||||
console.log("Loaded datarooms:", dataroomNames);
|
||||
} catch (error) {
|
||||
console.error("Error loading temas:", error);
|
||||
console.error("Error loading datarooms:", error);
|
||||
// Fallback to legacy getTemas if dataroom endpoint fails
|
||||
try {
|
||||
console.log("Falling back to legacy getTemas endpoint");
|
||||
const legacyResponse = await api.getTemas();
|
||||
const legacyTemas = Array.isArray(legacyResponse?.temas)
|
||||
? legacyResponse.temas.filter(Boolean)
|
||||
: [];
|
||||
setTemas(legacyTemas);
|
||||
console.log("Loaded legacy temas:", legacyTemas);
|
||||
} catch (legacyError) {
|
||||
console.error("Error loading legacy temas:", legacyError);
|
||||
// Ensure we always set an array, never undefined or null
|
||||
setTemas([]);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -85,8 +170,9 @@ export function Sidebar({
|
||||
e.stopPropagation(); // Evitar que se seleccione el tema al hacer clic en el icono
|
||||
|
||||
const confirmed = window.confirm(
|
||||
`¿Estás seguro de que deseas eliminar el tema "${tema}"?\n\n` +
|
||||
`¿Estás seguro de que deseas eliminar el dataroom "${tema}"?\n\n` +
|
||||
`Esto eliminará:\n` +
|
||||
`• El dataroom de la base de datos\n` +
|
||||
`• Todos los archivos del tema en Azure Blob Storage\n` +
|
||||
`• La colección "${tema}" en Qdrant (si existe)\n\n` +
|
||||
`Esta acción no se puede deshacer.`,
|
||||
@@ -97,35 +183,44 @@ export function Sidebar({
|
||||
try {
|
||||
setDeletingTema(tema);
|
||||
|
||||
// 1. Eliminar todos los archivos del tema en Azure Blob Storage
|
||||
await api.deleteTema(tema);
|
||||
|
||||
// 2. Intentar eliminar la colección en Qdrant (si existe)
|
||||
// 1. Delete the dataroom (this will also delete the vector collection)
|
||||
try {
|
||||
const collectionExists = await api.checkCollectionExists(tema);
|
||||
if (collectionExists.exists) {
|
||||
await api.deleteCollection(tema);
|
||||
console.log(`Colección "${tema}" eliminada de Qdrant`);
|
||||
}
|
||||
await api.deleteDataroom(tema);
|
||||
console.log(`Dataroom "${tema}" deleted successfully`);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`No se pudo eliminar la colección "${tema}" de Qdrant:`,
|
||||
error,
|
||||
);
|
||||
// Continuar aunque falle la eliminación de la colección
|
||||
console.error(`Error deleting dataroom "${tema}":`, error);
|
||||
// If dataroom deletion fails, fall back to legacy deletion
|
||||
console.log("Falling back to legacy deletion methods");
|
||||
|
||||
// Eliminar todos los archivos del tema en Azure Blob Storage
|
||||
await api.deleteTema(tema);
|
||||
|
||||
// Intentar eliminar la colección en Qdrant (si existe)
|
||||
try {
|
||||
const collectionExists = await api.checkCollectionExists(tema);
|
||||
if (collectionExists.exists) {
|
||||
await api.deleteCollection(tema);
|
||||
console.log(`Colección "${tema}" eliminada de Qdrant`);
|
||||
}
|
||||
} catch (collectionError) {
|
||||
console.warn(
|
||||
`No se pudo eliminar la colección "${tema}" de Qdrant:`,
|
||||
collectionError,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Actualizar la lista de temas
|
||||
// 2. Actualizar la lista de temas
|
||||
await loadTemas();
|
||||
|
||||
// 4. Si el tema eliminado estaba seleccionado, deseleccionar
|
||||
// 3. Si el tema eliminado estaba seleccionado, deseleccionar
|
||||
if (selectedTema === tema) {
|
||||
setSelectedTema(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error eliminando tema "${tema}":`, error);
|
||||
console.error(`Error eliminando dataroom "${tema}":`, error);
|
||||
alert(
|
||||
`Error al eliminar el tema: ${error instanceof Error ? error.message : "Error desconocido"}`,
|
||||
`Error al eliminar el dataroom: ${error instanceof Error ? error.message : "Error desconocido"}`,
|
||||
);
|
||||
} finally {
|
||||
setDeletingTema(null);
|
||||
@@ -174,14 +269,39 @@ export function Sidebar({
|
||||
{/* Temas List */}
|
||||
<div className={cn("flex-1 overflow-y-auto p-4", collapsed && "px-2")}>
|
||||
<div className="space-y-1">
|
||||
<h2
|
||||
<div
|
||||
className={cn(
|
||||
"text-sm font-medium text-gray-500 mb-3",
|
||||
collapsed && "text-xs text-center",
|
||||
"mb-3 flex items-center",
|
||||
collapsed ? "justify-center" : "justify-between",
|
||||
)}
|
||||
>
|
||||
{collapsed ? "Coll." : "Collections"}
|
||||
</h2>
|
||||
<h2
|
||||
className={cn(
|
||||
"text-sm font-medium text-gray-500",
|
||||
collapsed && "text-xs text-center",
|
||||
)}
|
||||
>
|
||||
{collapsed ? "Rooms" : "Datarooms"}
|
||||
</h2>
|
||||
{renderWithTooltip(
|
||||
"Crear dataroom",
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={cn(
|
||||
"gap-2",
|
||||
collapsed
|
||||
? "h-10 w-10 p-0 justify-center rounded-full"
|
||||
: "",
|
||||
)}
|
||||
onClick={() => handleCreateDialogOpenChange(true)}
|
||||
disabled={disabled || creatingDataroom}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
{!collapsed && <span>Crear dataroom</span>}
|
||||
</Button>,
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Todos los archivos */}
|
||||
{renderWithTooltip(
|
||||
@@ -207,7 +327,7 @@ export function Sidebar({
|
||||
<div className="text-sm text-gray-500 px-3 py-2 text-center">
|
||||
{collapsed ? "..." : "Cargando..."}
|
||||
</div>
|
||||
) : (
|
||||
) : Array.isArray(temas) && temas.length > 0 ? (
|
||||
temas.map((tema) => (
|
||||
<div key={tema} className="relative group">
|
||||
{renderWithTooltip(
|
||||
@@ -234,13 +354,19 @@ export function Sidebar({
|
||||
onClick={(e) => handleDeleteTema(tema, e)}
|
||||
disabled={deletingTema === tema || disabled}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 rounded hover:bg-red-100 opacity-0 group-hover:opacity-100 transition-opacity disabled:opacity-50"
|
||||
title="Eliminar tema y colección"
|
||||
title="Eliminar dataroom y colección"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 text-red-600" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="text-sm text-gray-500 px-3 py-2 text-center">
|
||||
{Array.isArray(temas) && temas.length === 0
|
||||
? "No hay datarooms"
|
||||
: "Cargando datarooms..."}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -272,7 +398,7 @@ export function Sidebar({
|
||||
</Button>,
|
||||
)}
|
||||
{renderWithTooltip(
|
||||
"Actualizar temas",
|
||||
"Actualizar datarooms",
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -285,12 +411,63 @@ export function Sidebar({
|
||||
>
|
||||
<RefreshCcw className={cn("mr-2 h-4 w-4", collapsed && "mr-0")} />
|
||||
<span className={cn(collapsed && "sr-only")}>
|
||||
Actualizar temas
|
||||
Actualizar datarooms
|
||||
</span>
|
||||
</Button>,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Dialog
|
||||
open={createDialogOpen}
|
||||
onOpenChange={handleCreateDialogOpenChange}
|
||||
>
|
||||
<DialogContent
|
||||
className="max-w-sm"
|
||||
aria-describedby="create-dataroom-description"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Crear dataroom</DialogTitle>
|
||||
<DialogDescription id="create-dataroom-description">
|
||||
Define un nombre único para organizar tus archivos.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="dataroom-name">Nombre del dataroom</Label>
|
||||
<Input
|
||||
id="dataroom-name"
|
||||
value={newDataroomName}
|
||||
onChange={(e) => {
|
||||
setNewDataroomName(e.target.value);
|
||||
if (createError) {
|
||||
setCreateError(null);
|
||||
}
|
||||
}}
|
||||
placeholder="Ej: normativa, contratos, fiscal..."
|
||||
autoFocus
|
||||
/>
|
||||
{createError && (
|
||||
<p className="text-sm text-red-500">{createError}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter className="mt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => handleCreateDialogOpenChange(false)}
|
||||
disabled={creatingDataroom}
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleCreateDataroom}
|
||||
disabled={creatingDataroom || newDataroomName.trim() === ""}
|
||||
>
|
||||
{creatingDataroom ? "Creando..." : "Crear dataroom"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,191 +1,275 @@
|
||||
const API_BASE_URL = 'http://localhost:8000/api/v1'
|
||||
const API_BASE_URL = "/api/v1";
|
||||
|
||||
interface FileUploadResponse {
|
||||
success: boolean
|
||||
message: string
|
||||
success: boolean;
|
||||
message: string;
|
||||
file?: {
|
||||
name: string
|
||||
full_path: string
|
||||
tema: string
|
||||
size: number
|
||||
last_modified: string
|
||||
url?: string
|
||||
}
|
||||
name: string;
|
||||
full_path: string;
|
||||
tema: string;
|
||||
size: number;
|
||||
last_modified: string;
|
||||
url?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface FileListResponse {
|
||||
files: Array<{
|
||||
name: string
|
||||
full_path: string
|
||||
tema: string
|
||||
size: number
|
||||
last_modified: string
|
||||
content_type?: string
|
||||
}>
|
||||
total: number
|
||||
tema?: string
|
||||
name: string;
|
||||
full_path: string;
|
||||
tema: string;
|
||||
size: number;
|
||||
last_modified: string;
|
||||
content_type?: string;
|
||||
}>;
|
||||
total: number;
|
||||
tema?: string;
|
||||
}
|
||||
|
||||
interface TemasResponse {
|
||||
temas: string[]
|
||||
total: number
|
||||
temas: string[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface DataroomsResponse {
|
||||
datarooms: Array<{
|
||||
name: string;
|
||||
collection: string;
|
||||
storage: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface CreateDataroomRequest {
|
||||
name: string;
|
||||
collection?: string;
|
||||
storage?: string;
|
||||
}
|
||||
|
||||
// API calls
|
||||
export const api = {
|
||||
// Obtener todos los temas
|
||||
// Obtener todos los temas (legacy)
|
||||
getTemas: async (): Promise<TemasResponse> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/temas`)
|
||||
if (!response.ok) throw new Error('Error fetching temas')
|
||||
return response.json()
|
||||
const response = await fetch(`${API_BASE_URL}/files/temas`);
|
||||
if (!response.ok) throw new Error("Error fetching temas");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Obtener todos los datarooms
|
||||
getDatarooms: async (): Promise<DataroomsResponse> => {
|
||||
console.log("Fetching datarooms from:", `${API_BASE_URL}/dataroom/`);
|
||||
const response = await fetch(`${API_BASE_URL}/dataroom/`);
|
||||
console.log("Datarooms response status:", response.status);
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error("Datarooms fetch error:", errorText);
|
||||
throw new Error("Error fetching datarooms");
|
||||
}
|
||||
const data = await response.json();
|
||||
console.log("Datarooms API response:", data);
|
||||
return data;
|
||||
},
|
||||
|
||||
// Crear un nuevo dataroom
|
||||
createDataroom: async (
|
||||
data: CreateDataroomRequest,
|
||||
): Promise<{
|
||||
message: string;
|
||||
dataroom: {
|
||||
name: string;
|
||||
collection: string;
|
||||
storage: string;
|
||||
};
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/dataroom/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) throw new Error("Error creating dataroom");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Eliminar un dataroom
|
||||
deleteDataroom: async (
|
||||
dataroomName: string,
|
||||
): Promise<{
|
||||
message: string;
|
||||
dataroom_name: string;
|
||||
}> => {
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/dataroom/${encodeURIComponent(dataroomName)}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
);
|
||||
if (!response.ok) throw new Error("Error deleting dataroom");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Obtener archivos (todos o por tema)
|
||||
getFiles: async (tema?: string): Promise<FileListResponse> => {
|
||||
const url = tema
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/files/?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/files/`
|
||||
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error('Error fetching files')
|
||||
return response.json()
|
||||
: `${API_BASE_URL}/files/`;
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Error fetching files");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Subir archivo
|
||||
uploadFile: async (file: File, tema?: string): Promise<FileUploadResponse> => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (tema) formData.append('tema', tema)
|
||||
uploadFile: async (
|
||||
file: File,
|
||||
tema?: string,
|
||||
): Promise<FileUploadResponse> => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
if (tema) formData.append("tema", tema);
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/files/upload`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
|
||||
if (!response.ok) throw new Error('Error uploading file')
|
||||
return response.json()
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error("Error uploading file");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Eliminar archivo
|
||||
deleteFile: async (filename: string, tema?: string): Promise<void> => {
|
||||
const url = tema
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/files/${encodeURIComponent(filename)}?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}`
|
||||
|
||||
const response = await fetch(url, { method: 'DELETE' })
|
||||
if (!response.ok) throw new Error('Error deleting file')
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}`;
|
||||
|
||||
const response = await fetch(url, { method: "DELETE" });
|
||||
if (!response.ok) throw new Error("Error deleting file");
|
||||
},
|
||||
|
||||
// Eliminar múltiples archivos
|
||||
deleteFiles: async (filenames: string[], tema?: string): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/delete-batch`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
files: filenames,
|
||||
tema: tema
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) throw new Error('Error deleting files')
|
||||
},
|
||||
|
||||
// Eliminar tema completo
|
||||
deleteTema: async (tema: string): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/tema/${encodeURIComponent(tema)}/delete-all`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
if (!response.ok) throw new Error('Error deleting tema')
|
||||
},
|
||||
|
||||
// Descargar archivo individual
|
||||
downloadFile: async (filename: string, tema?: string): Promise<void> => {
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/files/${encodeURIComponent(filename)}/download?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}/download`
|
||||
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error('Error downloading file')
|
||||
|
||||
// Crear blob y descargar
|
||||
const blob = await response.blob()
|
||||
const downloadUrl = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = downloadUrl
|
||||
link.download = filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(downloadUrl)
|
||||
},
|
||||
|
||||
// Descargar múltiples archivos como ZIP
|
||||
downloadMultipleFiles: async (filenames: string[], tema?: string, zipName?: string): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/download-batch`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
files: filenames,
|
||||
tema: tema,
|
||||
zip_name: zipName || 'archivos'
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) throw new Error('Error downloading files')
|
||||
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error("Error deleting files");
|
||||
},
|
||||
|
||||
// Eliminar tema completo
|
||||
deleteTema: async (tema: string): Promise<void> => {
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/files/tema/${encodeURIComponent(tema)}/delete-all`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Error deleting tema");
|
||||
},
|
||||
|
||||
// Descargar archivo individual
|
||||
downloadFile: async (filename: string, tema?: string): Promise<void> => {
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/files/${encodeURIComponent(filename)}/download?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}/download`;
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Error downloading file");
|
||||
|
||||
// Crear blob y descargar
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
},
|
||||
|
||||
// Descargar múltiples archivos como ZIP
|
||||
downloadMultipleFiles: async (
|
||||
filenames: string[],
|
||||
tema?: string,
|
||||
zipName?: string,
|
||||
): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/download-batch`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
files: filenames,
|
||||
tema: tema,
|
||||
zip_name: zipName || "archivos",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error("Error downloading files");
|
||||
|
||||
// Crear blob y descargar ZIP
|
||||
const blob = await response.blob()
|
||||
const downloadUrl = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = downloadUrl
|
||||
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
|
||||
// Obtener nombre del archivo del header Content-Disposition
|
||||
const contentDisposition = response.headers.get('Content-Disposition')
|
||||
const filename = contentDisposition?.split('filename=')[1]?.replace(/"/g, '') || 'archivos.zip'
|
||||
|
||||
link.download = filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(downloadUrl)
|
||||
const contentDisposition = response.headers.get("Content-Disposition");
|
||||
const filename =
|
||||
contentDisposition?.split("filename=")[1]?.replace(/"/g, "") ||
|
||||
"archivos.zip";
|
||||
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
},
|
||||
|
||||
// Descargar tema completo
|
||||
downloadTema: async (tema: string): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/files/tema/${encodeURIComponent(tema)}/download-all`)
|
||||
if (!response.ok) throw new Error('Error downloading tema')
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/files/tema/${encodeURIComponent(tema)}/download-all`,
|
||||
);
|
||||
if (!response.ok) throw new Error("Error downloading tema");
|
||||
|
||||
const blob = await response.blob()
|
||||
const downloadUrl = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = downloadUrl
|
||||
const blob = await response.blob();
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
|
||||
const contentDisposition = response.headers.get('Content-Disposition')
|
||||
const filename = contentDisposition?.split('filename=')[1]?.replace(/"/g, '') || `${tema}.zip`
|
||||
const contentDisposition = response.headers.get("Content-Disposition");
|
||||
const filename =
|
||||
contentDisposition?.split("filename=")[1]?.replace(/"/g, "") ||
|
||||
`${tema}.zip`;
|
||||
|
||||
link.download = filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(downloadUrl)
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
},
|
||||
|
||||
// Obtener URL temporal para preview de archivos
|
||||
getPreviewUrl: async (filename: string, tema?: string): Promise<string> => {
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/files/${encodeURIComponent(filename)}/preview-url?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}/preview-url`
|
||||
: `${API_BASE_URL}/files/${encodeURIComponent(filename)}/preview-url`;
|
||||
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error('Error getting preview URL')
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Error getting preview URL");
|
||||
|
||||
const data = await response.json()
|
||||
return data.url
|
||||
const data = await response.json();
|
||||
return data.url;
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
@@ -193,139 +277,178 @@ export const api = {
|
||||
// ============================================================================
|
||||
|
||||
// Health check de la base de datos vectorial
|
||||
vectorHealthCheck: async (): Promise<{ status: string; db_type: string; message: string }> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/health`)
|
||||
if (!response.ok) throw new Error('Error checking vector DB health')
|
||||
return response.json()
|
||||
vectorHealthCheck: async (): Promise<{
|
||||
status: string;
|
||||
db_type: string;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/health`);
|
||||
if (!response.ok) throw new Error("Error checking vector DB health");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Verificar si una colección existe
|
||||
checkCollectionExists: async (collectionName: string): Promise<{ exists: boolean; collection_name: string }> => {
|
||||
checkCollectionExists: async (
|
||||
collectionName: string,
|
||||
): Promise<{ exists: boolean; collection_name: string }> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/collections/exists`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ collection_name: collectionName }),
|
||||
})
|
||||
if (!response.ok) throw new Error('Error checking collection')
|
||||
return response.json()
|
||||
});
|
||||
if (!response.ok) throw new Error("Error checking collection");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Crear una nueva colección
|
||||
createCollection: async (
|
||||
collectionName: string,
|
||||
vectorSize: number = 3072,
|
||||
distance: string = 'Cosine'
|
||||
): Promise<{ success: boolean; collection_name: string; message: string }> => {
|
||||
distance: string = "Cosine",
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
collection_name: string;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/collections/create`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
collection_name: collectionName,
|
||||
vector_size: vectorSize,
|
||||
distance: distance,
|
||||
}),
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
throw new Error(error.detail || 'Error creating collection')
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail || "Error creating collection");
|
||||
}
|
||||
return response.json()
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Eliminar una colección
|
||||
deleteCollection: async (collectionName: string): Promise<{ success: boolean; collection_name: string; message: string }> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
if (!response.ok) throw new Error('Error deleting collection')
|
||||
return response.json()
|
||||
deleteCollection: async (
|
||||
collectionName: string,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
collection_name: string;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
);
|
||||
if (!response.ok) throw new Error("Error deleting collection");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Obtener información de una colección
|
||||
getCollectionInfo: async (collectionName: string): Promise<{
|
||||
name: string
|
||||
vectors_count: number
|
||||
vectors_config: { size: number; distance: string }
|
||||
status: string
|
||||
getCollectionInfo: async (
|
||||
collectionName: string,
|
||||
): Promise<{
|
||||
name: string;
|
||||
vectors_count: number;
|
||||
vectors_config: { size: number; distance: string };
|
||||
status: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/info`)
|
||||
if (!response.ok) throw new Error('Error getting collection info')
|
||||
return response.json()
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/info`,
|
||||
);
|
||||
if (!response.ok) throw new Error("Error getting collection info");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Verificar si un archivo existe en una colección
|
||||
checkFileExistsInCollection: async (
|
||||
collectionName: string,
|
||||
fileName: string
|
||||
): Promise<{ exists: boolean; collection_name: string; file_name: string; chunk_count?: number }> => {
|
||||
fileName: string,
|
||||
): Promise<{
|
||||
exists: boolean;
|
||||
collection_name: string;
|
||||
file_name: string;
|
||||
chunk_count?: number;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/files/exists`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
collection_name: collectionName,
|
||||
file_name: fileName,
|
||||
}),
|
||||
})
|
||||
if (!response.ok) throw new Error('Error checking file in collection')
|
||||
return response.json()
|
||||
});
|
||||
if (!response.ok) throw new Error("Error checking file in collection");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Obtener chunks de un archivo
|
||||
getChunksByFile: async (
|
||||
collectionName: string,
|
||||
fileName: string,
|
||||
limit?: number
|
||||
limit?: number,
|
||||
): Promise<{
|
||||
collection_name: string
|
||||
file_name: string
|
||||
chunks: Array<{ id: string; payload: any; vector?: number[] }>
|
||||
total_chunks: number
|
||||
collection_name: string;
|
||||
file_name: string;
|
||||
chunks: Array<{ id: string; payload: any; vector?: number[] }>;
|
||||
total_chunks: number;
|
||||
}> => {
|
||||
const url = limit
|
||||
? `${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/files/${encodeURIComponent(fileName)}/chunks?limit=${limit}`
|
||||
: `${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/files/${encodeURIComponent(fileName)}/chunks`
|
||||
: `${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/files/${encodeURIComponent(fileName)}/chunks`;
|
||||
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error('Error getting chunks')
|
||||
return response.json()
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Error getting chunks");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Eliminar archivo de colección
|
||||
deleteFileFromCollection: async (
|
||||
collectionName: string,
|
||||
fileName: string
|
||||
): Promise<{ success: boolean; collection_name: string; file_name: string; chunks_deleted: number; message: string }> => {
|
||||
fileName: string,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
collection_name: string;
|
||||
file_name: string;
|
||||
chunks_deleted: number;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/vectors/collections/${encodeURIComponent(collectionName)}/files/${encodeURIComponent(fileName)}`,
|
||||
{ method: 'DELETE' }
|
||||
)
|
||||
if (!response.ok) throw new Error('Error deleting file from collection')
|
||||
return response.json()
|
||||
{ method: "DELETE" },
|
||||
);
|
||||
if (!response.ok) throw new Error("Error deleting file from collection");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Agregar chunks a una colección
|
||||
addChunks: async (
|
||||
collectionName: string,
|
||||
chunks: Array<{ id: string; vector: number[]; payload: any }>
|
||||
): Promise<{ success: boolean; collection_name: string; chunks_added: number; message: string }> => {
|
||||
chunks: Array<{ id: string; vector: number[]; payload: any }>,
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
collection_name: string;
|
||||
chunks_added: number;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/vectors/chunks/add`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
collection_name: collectionName,
|
||||
chunks: chunks,
|
||||
}),
|
||||
})
|
||||
if (!response.ok) throw new Error('Error adding chunks')
|
||||
return response.json()
|
||||
});
|
||||
if (!response.ok) throw new Error("Error adding chunks");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
@@ -335,89 +458,89 @@ export const api = {
|
||||
// Obtener perfiles de chunking predefinidos
|
||||
getChunkingProfiles: async (): Promise<{
|
||||
profiles: Array<{
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
max_tokens: number
|
||||
target_tokens: number
|
||||
chunk_size: number
|
||||
chunk_overlap: number
|
||||
use_llm: boolean
|
||||
}>
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
max_tokens: number;
|
||||
target_tokens: number;
|
||||
chunk_size: number;
|
||||
chunk_overlap: number;
|
||||
use_llm: boolean;
|
||||
}>;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/chunking/profiles`)
|
||||
if (!response.ok) throw new Error('Error fetching chunking profiles')
|
||||
return response.json()
|
||||
const response = await fetch(`${API_BASE_URL}/chunking/profiles`);
|
||||
if (!response.ok) throw new Error("Error fetching chunking profiles");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Generar preview de chunks (hasta 3 chunks)
|
||||
generateChunkPreview: async (config: {
|
||||
file_name: string
|
||||
tema: string
|
||||
max_tokens?: number
|
||||
target_tokens?: number
|
||||
chunk_size?: number
|
||||
chunk_overlap?: number
|
||||
use_llm?: boolean
|
||||
custom_instructions?: string
|
||||
file_name: string;
|
||||
tema: string;
|
||||
max_tokens?: number;
|
||||
target_tokens?: number;
|
||||
chunk_size?: number;
|
||||
chunk_overlap?: number;
|
||||
use_llm?: boolean;
|
||||
custom_instructions?: string;
|
||||
}): Promise<{
|
||||
success: boolean
|
||||
file_name: string
|
||||
tema: string
|
||||
success: boolean;
|
||||
file_name: string;
|
||||
tema: string;
|
||||
chunks: Array<{
|
||||
index: number
|
||||
text: string
|
||||
page: number
|
||||
file_name: string
|
||||
tokens: number
|
||||
}>
|
||||
message: string
|
||||
index: number;
|
||||
text: string;
|
||||
page: number;
|
||||
file_name: string;
|
||||
tokens: number;
|
||||
}>;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/chunking/preview`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(config),
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
throw new Error(error.detail || 'Error generating preview')
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail || "Error generating preview");
|
||||
}
|
||||
return response.json()
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Procesar PDF completo
|
||||
processChunkingFull: async (config: {
|
||||
file_name: string
|
||||
tema: string
|
||||
collection_name: string
|
||||
max_tokens?: number
|
||||
target_tokens?: number
|
||||
chunk_size?: number
|
||||
chunk_overlap?: number
|
||||
use_llm?: boolean
|
||||
custom_instructions?: string
|
||||
file_name: string;
|
||||
tema: string;
|
||||
collection_name: string;
|
||||
max_tokens?: number;
|
||||
target_tokens?: number;
|
||||
chunk_size?: number;
|
||||
chunk_overlap?: number;
|
||||
use_llm?: boolean;
|
||||
custom_instructions?: string;
|
||||
}): Promise<{
|
||||
success: boolean
|
||||
collection_name: string
|
||||
file_name: string
|
||||
total_chunks: number
|
||||
chunks_added: number
|
||||
message: string
|
||||
success: boolean;
|
||||
collection_name: string;
|
||||
file_name: string;
|
||||
total_chunks: number;
|
||||
chunks_added: number;
|
||||
message: string;
|
||||
}> => {
|
||||
const response = await fetch(`${API_BASE_URL}/chunking/process`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(config),
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
throw new Error(error.detail || 'Error processing PDF')
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail || "Error processing PDF");
|
||||
}
|
||||
return response.json()
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
@@ -427,62 +550,62 @@ export const api = {
|
||||
// Crear schema
|
||||
createSchema: async (schema: any): Promise<any> => {
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(schema)
|
||||
})
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(schema),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
throw new Error(error.detail?.message || 'Error creando schema')
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail?.message || "Error creando schema");
|
||||
}
|
||||
return response.json()
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Listar schemas
|
||||
listSchemas: async (tema?: string): Promise<any[]> => {
|
||||
const url = tema
|
||||
? `${API_BASE_URL}/schemas/?tema=${encodeURIComponent(tema)}`
|
||||
: `${API_BASE_URL}/schemas/`
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error('Error listando schemas')
|
||||
return response.json()
|
||||
: `${API_BASE_URL}/schemas/`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Error listando schemas");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Obtener schema por ID
|
||||
getSchema: async (schema_id: string): Promise<any> => {
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/${schema_id}`)
|
||||
if (!response.ok) throw new Error('Error obteniendo schema')
|
||||
return response.json()
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/${schema_id}`);
|
||||
if (!response.ok) throw new Error("Error obteniendo schema");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Actualizar schema
|
||||
updateSchema: async (schema_id: string, schema: any): Promise<any> => {
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/${schema_id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(schema)
|
||||
})
|
||||
if (!response.ok) throw new Error('Error actualizando schema')
|
||||
return response.json()
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(schema),
|
||||
});
|
||||
if (!response.ok) throw new Error("Error actualizando schema");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// Eliminar schema
|
||||
deleteSchema: async (schema_id: string): Promise<void> => {
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/${schema_id}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
if (!response.ok) throw new Error('Error eliminando schema')
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!response.ok) throw new Error("Error eliminando schema");
|
||||
},
|
||||
|
||||
// Validar schema
|
||||
validateSchema: async (schema: any): Promise<any> => {
|
||||
const response = await fetch(`${API_BASE_URL}/schemas/validate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(schema)
|
||||
})
|
||||
if (!response.ok) throw new Error('Error validando schema')
|
||||
return response.json()
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(schema),
|
||||
});
|
||||
if (!response.ok) throw new Error("Error validando schema");
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
@@ -491,25 +614,24 @@ export const api = {
|
||||
|
||||
// Procesar con LandingAI
|
||||
processWithLandingAI: async (config: {
|
||||
file_name: string
|
||||
tema: string
|
||||
collection_name: string
|
||||
mode: 'quick' | 'extract'
|
||||
schema_id?: string
|
||||
include_chunk_types?: string[]
|
||||
max_tokens_per_chunk?: number
|
||||
merge_small_chunks?: boolean
|
||||
file_name: string;
|
||||
tema: string;
|
||||
collection_name: string;
|
||||
mode: "quick" | "extract";
|
||||
schema_id?: string;
|
||||
include_chunk_types?: string[];
|
||||
max_tokens_per_chunk?: number;
|
||||
merge_small_chunks?: boolean;
|
||||
}): Promise<any> => {
|
||||
const response = await fetch(`${API_BASE_URL}/chunking-landingai/process`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(config)
|
||||
})
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json()
|
||||
throw new Error(error.detail || 'Error procesando con LandingAI')
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail || "Error procesando con LandingAI");
|
||||
}
|
||||
return response.json()
|
||||
return response.json();
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user