Notas en frontend funcionando y pudiendo subir mas por sus endpoints
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "255345d5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from src.TextManager.biblioteca import Biblioteca\n",
|
||||
"from src.TextManager.biblioteca_mmr import BibliotecaRepo\n",
|
||||
"from src.Llms.Embedders.Openai_embedder import OpenAIEmbedder\n",
|
||||
"from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo\n",
|
||||
"from src.ConexionSql.Postgres_conexion import PostgresConexion\n",
|
||||
"from src.TextManager.nota import Nota\n",
|
||||
"from src.TextManager.notas_biblioteca_mmr import generar_tabla_nota_para_biblioteca, NotaRepo\n",
|
||||
"from sqlalchemy import MetaData\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "b414a66c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def agregar_nota_a_biblioteca(\n",
|
||||
" conexion: PostgresConexion,\n",
|
||||
" biblioteca_id: str,\n",
|
||||
" titulo: str,\n",
|
||||
" texto: str = \"\",\n",
|
||||
" tags: list[str] = None,\n",
|
||||
" conexiones: list[str] = None,\n",
|
||||
" resumen: str = \"\"\n",
|
||||
"):\n",
|
||||
" print(\"[INFO] Iniciando el proceso de agregar nota a la biblioteca...\")\n",
|
||||
"\n",
|
||||
" # Obtener la biblioteca\n",
|
||||
" print(f\"[INFO] Buscando biblioteca con ID: {biblioteca_id}\")\n",
|
||||
" repo_biblioteca = BibliotecaRepo(conexion)\n",
|
||||
" biblioteca = repo_biblioteca.get_by_id(biblioteca_id)\n",
|
||||
" if biblioteca is None:\n",
|
||||
" print(f\"[ERROR] No se encontró la biblioteca con ID {biblioteca_id}\")\n",
|
||||
" raise ValueError(f\"No se encontró la biblioteca con ID {biblioteca_id}\")\n",
|
||||
" print(f\"[INFO] Biblioteca encontrada: {biblioteca.nombre} (vector_dim={biblioteca.vector_dim})\")\n",
|
||||
"\n",
|
||||
" # Crear objeto Nota\n",
|
||||
" print(f\"[INFO] Creando objeto Nota con título: {titulo}\")\n",
|
||||
" nota = Nota(\n",
|
||||
" titulo=titulo,\n",
|
||||
" texto=texto,\n",
|
||||
" tags=tags or [],\n",
|
||||
" conexiones=conexiones or [],\n",
|
||||
" resumen=resumen or \"\",\n",
|
||||
" # vector=biblioteca.embedder.embed_text(texto),\n",
|
||||
" # vector_resumen=biblioteca.embedder.embed_text(resumen) if resumen else None\n",
|
||||
" )\n",
|
||||
" # Mostrar atributos seguros\n",
|
||||
" print(\n",
|
||||
" f\"[DEBUG] Nota creada: titulo='{nota.titulo}', \"\n",
|
||||
" f\"texto_len={len(nota.texto)}, \"\n",
|
||||
" f\"tags={len(nota.tags)}, \"\n",
|
||||
" f\"conexiones={len(nota.conexiones)}, \"\n",
|
||||
" f\"resumen_len={len(nota.resumen)}\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # Preparar tabla y modelo de nota\n",
|
||||
" print(f\"[INFO] Generando tabla y modelo de Nota para la biblioteca: {biblioteca.nombre}\")\n",
|
||||
" metadata = MetaData()\n",
|
||||
" tabla, ModeloNota = generar_tabla_nota_para_biblioteca(\n",
|
||||
" biblioteca.nombre,\n",
|
||||
" biblioteca.vector_dim,\n",
|
||||
" metadata\n",
|
||||
" )\n",
|
||||
" print(f\"[INFO] Creando tabla en la base de datos si no existe...\")\n",
|
||||
" metadata.create_all(conexion.get_engine())\n",
|
||||
" print(f\"[INFO] Tabla '{tabla.name}' verificada/creada.\")\n",
|
||||
"\n",
|
||||
" # Guardar la nota\n",
|
||||
" print(f\"[INFO] Guardando nota en la base de datos...\")\n",
|
||||
" repo_nota = NotaRepo(conexion.get_session(), ModeloNota)\n",
|
||||
" nota_id = repo_nota.add(nota)\n",
|
||||
" print(f\"[INFO] Nota guardada con ID: {nota_id}\")\n",
|
||||
"\n",
|
||||
" resultado = {\n",
|
||||
" \"mensaje\": f\"Nota '{titulo}' agregada con éxito a la biblioteca '{biblioteca.nombre}'.\",\n",
|
||||
" \"nota_id\": nota_id\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" print(f\"[SUCCESS] {resultado['mensaje']}\")\n",
|
||||
" return resultado\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "8e57e511",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[INFO] Iniciando el proceso de agregar nota a la biblioteca...\n",
|
||||
"[INFO] Buscando biblioteca con ID: BBLI20250511-a91dbb2168172979414\n",
|
||||
"[INFO] Biblioteca encontrada: biblio_Pruebas_1 (vector_dim=3072)\n",
|
||||
"[INFO] Creando objeto Nota con título: sajdhasjdhasjdh\n",
|
||||
"[DEBUG] Nota creada: titulo='sajdhasjdhasjdh', texto_len=0, tags=0, conexiones=0, resumen_len=0\n",
|
||||
"[INFO] Generando tabla y modelo de Nota para la biblioteca: biblio_Pruebas_1\n",
|
||||
"[INFO] Creando tabla en la base de datos si no existe...\n",
|
||||
"[INFO] Tabla 'biblio_pruebas_1' verificada/creada.\n",
|
||||
"[INFO] Guardando nota en la base de datos...\n",
|
||||
"[INFO] Nota guardada con ID: NOTA20250511-04dbb203a9126228444\n",
|
||||
"[SUCCESS] Nota 'sajdhasjdhasjdh' agregada con éxito a la biblioteca 'biblio_Pruebas_1'.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'mensaje': \"Nota 'sajdhasjdhasjdh' agregada con éxito a la biblioteca 'biblio_Pruebas_1'.\",\n",
|
||||
" 'nota_id': 'NOTA20250511-04dbb203a9126228444'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from entrypoint.init_db import db_credencial\n",
|
||||
"conexion_admin = PostgresConexion(db_credencial)\n",
|
||||
"\n",
|
||||
"agregar_nota_a_biblioteca(\n",
|
||||
" conexion=conexion_admin,\n",
|
||||
" biblioteca_id=\"BBLI20250511-a91dbb2168172979414\",\n",
|
||||
" titulo=\"sajdhasjdhasjdh\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "431f24f1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def listar_notas_de_biblioteca(conexion: PostgresConexion, biblioteca_id: str) -> list[dict]:\n",
|
||||
" repo_biblioteca = BibliotecaRepo(conexion)\n",
|
||||
" biblioteca = repo_biblioteca.get_by_id(biblioteca_id)\n",
|
||||
" if not biblioteca:\n",
|
||||
" raise ValueError(f\"No se encontró la biblioteca con ID: {biblioteca_id}\")\n",
|
||||
"\n",
|
||||
" metadata = MetaData()\n",
|
||||
" tabla, ModeloNota = generar_tabla_nota_para_biblioteca(biblioteca.nombre, biblioteca.vector_dim, metadata)\n",
|
||||
" metadata.create_all(conexion.get_engine())\n",
|
||||
"\n",
|
||||
" repo_nota = NotaRepo(conexion.get_session(), ModeloNota)\n",
|
||||
" notas = repo_nota.get_all()\n",
|
||||
" return [\n",
|
||||
" {\n",
|
||||
" \"id\": n.id,\n",
|
||||
" \"titulo\": n.titulo,\n",
|
||||
" \"tags\": n.tags,\n",
|
||||
" \"texto\": n.texto,\n",
|
||||
" \"resumen\": n.resumen,\n",
|
||||
" \"conexiones\": n.conexiones\n",
|
||||
" }\n",
|
||||
" for n in notas\n",
|
||||
" ]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "ae4f2994",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"E:\\Fitz_Studio\\src\\TextManager\\notas_biblioteca_mmr.py:51: SAWarning: This declarative base already contains a class with the same class name and module name as src.TextManager.notas_biblioteca_mmr.NotaModel, and will be replaced in the string-lookup table.\n",
|
||||
" mapper_registry.map_imperatively(NotaModel, tabla)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "TypeError",
|
||||
"evalue": "'NoneType' object is not iterable",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
|
||||
"\u001b[31mTypeError\u001b[39m Traceback (most recent call last)",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[14]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mlistar_notas_de_biblioteca\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 2\u001b[39m \u001b[43m \u001b[49m\u001b[43mconexion\u001b[49m\u001b[43m=\u001b[49m\u001b[43mconexion_admin\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 3\u001b[39m \u001b[43m \u001b[49m\u001b[43mbiblioteca_id\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mBBLI20250511-a91dbb2168172979414\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\n\u001b[32m 4\u001b[39m \u001b[43m)\u001b[49m\n",
|
||||
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[13]\u001b[39m\u001b[32m, line 12\u001b[39m, in \u001b[36mlistar_notas_de_biblioteca\u001b[39m\u001b[34m(conexion, biblioteca_id)\u001b[39m\n\u001b[32m 9\u001b[39m metadata.create_all(conexion.get_engine())\n\u001b[32m 11\u001b[39m repo_nota = NotaRepo(conexion.get_session(), ModeloNota)\n\u001b[32m---> \u001b[39m\u001b[32m12\u001b[39m notas = \u001b[43mrepo_nota\u001b[49m\u001b[43m.\u001b[49m\u001b[43mget_all\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 13\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m [\n\u001b[32m 14\u001b[39m {\n\u001b[32m 15\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mid\u001b[39m\u001b[33m\"\u001b[39m: n.id,\n\u001b[32m (...)\u001b[39m\u001b[32m 22\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m notas\n\u001b[32m 23\u001b[39m ]\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32mE:\\Fitz_Studio\\src\\TextManager\\notas_biblioteca_mmr.py:109\u001b[39m, in \u001b[36mget_all\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 0\u001b[39m <Error retrieving source code with stack_data see ipython/ipython#13598>\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32mE:\\Fitz_Studio\\src\\TextManager\\notas_biblioteca_mmr.py:109\u001b[39m, in \u001b[36m<listcomp>\u001b[39m\u001b[34m(.0)\u001b[39m\n\u001b[32m 0\u001b[39m <Error retrieving source code with stack_data see ipython/ipython#13598>\n",
|
||||
"\u001b[36mFile \u001b[39m\u001b[32mE:\\Fitz_Studio\\src\\TextManager\\notas_biblioteca_mmr.py:82\u001b[39m, in \u001b[36mfrom_model\u001b[39m\u001b[34m(model)\u001b[39m\n\u001b[32m 76\u001b[39m \u001b[38;5;129m@staticmethod\u001b[39m\n\u001b[32m 77\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mfrom_model\u001b[39m(model) -> Nota:\n\u001b[32m 78\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m Nota(\n\u001b[32m 79\u001b[39m \u001b[38;5;28mid\u001b[39m=model.id,\n\u001b[32m 80\u001b[39m titulo=model.titulo,\n\u001b[32m 81\u001b[39m tags=model.tags.split(\u001b[33m\"\u001b[39m\u001b[33m,\u001b[39m\u001b[33m\"\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m model.tags \u001b[38;5;28;01melse\u001b[39;00m [],\n\u001b[32m---> \u001b[39m\u001b[32m82\u001b[39m conexiones=model.conexiones.split(\u001b[33m\"\u001b[39m\u001b[33m,\u001b[39m\u001b[33m\"\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m model.conexiones \u001b[38;5;28;01melse\u001b[39;00m [],\n\u001b[32m 83\u001b[39m texto=model.texto,\n\u001b[32m 84\u001b[39m resumen=model.resumen,\n\u001b[32m 85\u001b[39m vector=\u001b[38;5;28mlist\u001b[39m(model.vector),\n\u001b[32m 86\u001b[39m vector_resumen=\u001b[38;5;28mlist\u001b[39m(model.vector_resumen) \u001b[38;5;28;01mif\u001b[39;00m model.vector_resumen \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 87\u001b[39m )\n",
|
||||
"\u001b[31mTypeError\u001b[39m: 'NoneType' object is not iterable"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"listar_notas_de_biblioteca(\n",
|
||||
" conexion=conexion_admin,\n",
|
||||
" biblioteca_id=\"BBLI20250511-a91dbb2168172979414\"\n",
|
||||
")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,21 +1,99 @@
|
||||
# backend/api/v1/biblioteca.py
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
from fastapi import Path
|
||||
|
||||
|
||||
from backend.db.conexion import get_conexion
|
||||
from backend.services.text_manager import crear_biblioteca
|
||||
from backend.services.text_manager import (
|
||||
crear_biblioteca,
|
||||
listar_bibliotecas,
|
||||
agregar_nota_a_biblioteca,
|
||||
listar_notas_de_biblioteca
|
||||
)
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# ---------------------------
|
||||
# MODELOS PARA BIBLIOTECAS
|
||||
# ---------------------------
|
||||
|
||||
class BibliotecaInput(BaseModel):
|
||||
nombre_biblioteca: str
|
||||
descripcion: str
|
||||
|
||||
@router.post("/")
|
||||
@router.post("/", summary="Crear una nueva biblioteca")
|
||||
def crear_biblioteca_endpoint(
|
||||
data: BibliotecaInput,
|
||||
conexion: PostgresConexion = Depends(get_conexion)
|
||||
):
|
||||
return crear_biblioteca(nombre_biblioteca=data.nombre_biblioteca,
|
||||
descripcion=data.descripcion,
|
||||
conexion=conexion)
|
||||
try:
|
||||
return crear_biblioteca(
|
||||
nombre_biblioteca=data.nombre_biblioteca,
|
||||
descripcion=data.descripcion,
|
||||
conexion=conexion
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Error interno al crear la biblioteca")
|
||||
|
||||
@router.get("/list", summary="Listar todas las bibliotecas")
|
||||
def listar_todas_bibliotecas(
|
||||
conexion: PostgresConexion = Depends(get_conexion)
|
||||
):
|
||||
try:
|
||||
return listar_bibliotecas(conexion=conexion)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Error interno al listar las bibliotecas")
|
||||
|
||||
# ---------------------------
|
||||
# MODELOS PARA NOTAS
|
||||
# ---------------------------
|
||||
|
||||
class NotaInput(BaseModel):
|
||||
titulo: str
|
||||
texto: str = ""
|
||||
tags: Optional[List[str]] = []
|
||||
conexiones: Optional[List[str]] = []
|
||||
resumen: Optional[str] = ""
|
||||
|
||||
|
||||
|
||||
@router.post("/nota/{biblioteca_id}", summary="Agregar una nota a una biblioteca")
|
||||
def agregar_nota(
|
||||
biblioteca_id: str = Path(..., description="ID de la biblioteca a la que se agregará la nota"),
|
||||
nota: NotaInput = ..., # viene del body
|
||||
conexion: PostgresConexion = Depends(get_conexion)
|
||||
):
|
||||
try:
|
||||
return agregar_nota_a_biblioteca(
|
||||
conexion=conexion,
|
||||
biblioteca_id=biblioteca_id,
|
||||
titulo=nota.titulo,
|
||||
texto=nota.texto,
|
||||
tags=nota.tags,
|
||||
conexiones=nota.conexiones,
|
||||
resumen=nota.resumen
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Error interno al agregar la nota")
|
||||
|
||||
|
||||
|
||||
@router.get("/nota/list/{biblioteca_id}", summary="Listar todas las notas de una biblioteca")
|
||||
def listar_notas(
|
||||
biblioteca_id: str,
|
||||
conexion: PostgresConexion = Depends(get_conexion)
|
||||
):
|
||||
try:
|
||||
return listar_notas_de_biblioteca(conexion, biblioteca_id)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Error interno al listar las notas")
|
||||
|
||||
@@ -3,8 +3,9 @@ from src.TextManager.biblioteca_mmr import BibliotecaRepo
|
||||
from src.Llms.Embedders.Openai_embedder import OpenAIEmbedder
|
||||
from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from backend.db.conexion import get_conexion
|
||||
|
||||
from src.TextManager.nota import Nota
|
||||
from src.TextManager.notas_biblioteca_mmr import generar_tabla_nota_para_biblioteca, NotaRepo
|
||||
from sqlalchemy import MetaData
|
||||
|
||||
def crear_biblioteca(nombre_biblioteca: str, conexion: PostgresConexion, descripcion: str):
|
||||
cred_repo = OpenAICredencialRepo(conexion)
|
||||
@@ -26,5 +27,106 @@ def crear_biblioteca(nombre_biblioteca: str, conexion: PostgresConexion, descrip
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
crear_biblioteca("hola_intento5")
|
||||
def listar_bibliotecas(conexion: PostgresConexion) -> list[dict]:
|
||||
repo = BibliotecaRepo(conexion)
|
||||
bibliotecas: list[Biblioteca] = repo.get_all()
|
||||
return [
|
||||
{
|
||||
"id": b.id,
|
||||
"nombre": b.nombre,
|
||||
"descripcion": b.descripcion,
|
||||
"vector_dim": b.vector_dim
|
||||
}
|
||||
for b in bibliotecas
|
||||
]
|
||||
|
||||
def agregar_nota_a_biblioteca(
|
||||
conexion: PostgresConexion,
|
||||
biblioteca_id: str,
|
||||
titulo: str,
|
||||
texto: str = "",
|
||||
tags: list[str] = None,
|
||||
conexiones: list[str] = None,
|
||||
resumen: str = ""
|
||||
):
|
||||
print("[INFO] Iniciando el proceso de agregar nota a la biblioteca...")
|
||||
|
||||
# Obtener la biblioteca
|
||||
print(f"[INFO] Buscando biblioteca con ID: {biblioteca_id}")
|
||||
repo_biblioteca = BibliotecaRepo(conexion)
|
||||
biblioteca = repo_biblioteca.get_by_id(biblioteca_id)
|
||||
if biblioteca is None:
|
||||
print(f"[ERROR] No se encontró la biblioteca con ID {biblioteca_id}")
|
||||
raise ValueError(f"No se encontró la biblioteca con ID {biblioteca_id}")
|
||||
print(f"[INFO] Biblioteca encontrada: {biblioteca.nombre} (vector_dim={biblioteca.vector_dim})")
|
||||
|
||||
# Crear objeto Nota
|
||||
print(f"[INFO] Creando objeto Nota con título: {titulo}")
|
||||
nota = Nota(
|
||||
titulo=titulo,
|
||||
texto=texto,
|
||||
tags=tags or [],
|
||||
conexiones=conexiones or [],
|
||||
resumen=resumen or "",
|
||||
# vector=biblioteca.embedder.embed_text(texto),
|
||||
# vector_resumen=biblioteca.embedder.embed_text(resumen) if resumen else None
|
||||
)
|
||||
# Mostrar atributos seguros
|
||||
print(
|
||||
f"[DEBUG] Nota creada: titulo='{nota.titulo}', "
|
||||
f"texto_len={len(nota.texto)}, "
|
||||
f"tags={len(nota.tags)}, "
|
||||
f"conexiones={len(nota.conexiones)}, "
|
||||
f"resumen_len={len(nota.resumen)}"
|
||||
)
|
||||
|
||||
# Preparar tabla y modelo de nota
|
||||
print(f"[INFO] Generando tabla y modelo de Nota para la biblioteca: {biblioteca.nombre}")
|
||||
metadata = MetaData()
|
||||
tabla, ModeloNota = generar_tabla_nota_para_biblioteca(
|
||||
biblioteca.nombre,
|
||||
biblioteca.vector_dim,
|
||||
metadata
|
||||
)
|
||||
print(f"[INFO] Creando tabla en la base de datos si no existe...")
|
||||
metadata.create_all(conexion.get_engine())
|
||||
print(f"[INFO] Tabla '{tabla.name}' verificada/creada.")
|
||||
|
||||
# Guardar la nota
|
||||
print(f"[INFO] Guardando nota en la base de datos...")
|
||||
repo_nota = NotaRepo(conexion.get_session(), ModeloNota)
|
||||
nota_id = repo_nota.add(nota)
|
||||
print(f"[INFO] Nota guardada con ID: {nota_id}")
|
||||
|
||||
resultado = {
|
||||
"mensaje": f"Nota '{titulo}' agregada con éxito a la biblioteca '{biblioteca.nombre}'.",
|
||||
"nota_id": nota_id
|
||||
}
|
||||
|
||||
print(f"[SUCCESS] {resultado['mensaje']}")
|
||||
return resultado
|
||||
|
||||
|
||||
def listar_notas_de_biblioteca(conexion: PostgresConexion, biblioteca_id: str) -> list[dict]:
|
||||
repo_biblioteca = BibliotecaRepo(conexion)
|
||||
biblioteca = repo_biblioteca.get_by_id(biblioteca_id)
|
||||
if not biblioteca:
|
||||
raise ValueError(f"No se encontró la biblioteca con ID: {biblioteca_id}")
|
||||
|
||||
metadata = MetaData()
|
||||
tabla, ModeloNota = generar_tabla_nota_para_biblioteca(biblioteca.nombre, biblioteca.vector_dim, metadata)
|
||||
metadata.create_all(conexion.get_engine())
|
||||
|
||||
repo_nota = NotaRepo(conexion.get_session(), ModeloNota)
|
||||
notas = repo_nota.get_all()
|
||||
return [
|
||||
{
|
||||
"id": n.id,
|
||||
"titulo": n.titulo,
|
||||
"tags": n.tags,
|
||||
"texto": n.texto,
|
||||
"resumen": n.resumen,
|
||||
"conexiones": n.conexiones
|
||||
}
|
||||
for n in notas
|
||||
]
|
||||
Generated
+101
-14
@@ -13,6 +13,7 @@
|
||||
"@react-three/fiber": "^9.1.2",
|
||||
"@tabler/icons": "^3.31.0",
|
||||
"@tabler/icons-react": "^3.31.0",
|
||||
"axios": "^1.9.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-rnd": "^10.5.2",
|
||||
@@ -3304,6 +3305,12 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
@@ -3330,6 +3337,17 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
|
||||
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axobject-query": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||
@@ -3552,7 +3570,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -3713,6 +3730,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -4053,6 +4082,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
@@ -4127,7 +4165,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
@@ -4279,7 +4316,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -4289,7 +4325,6 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -4334,7 +4369,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
@@ -4347,7 +4381,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -5061,6 +5094,26 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||
@@ -5094,6 +5147,42 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@@ -5133,7 +5222,6 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -5184,7 +5272,6 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -5218,7 +5305,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
@@ -5413,7 +5499,6 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -5492,7 +5577,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -5505,7 +5589,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
@@ -5521,7 +5604,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -6579,7 +6661,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7556,6 +7637,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@react-three/fiber": "^9.1.2",
|
||||
"@tabler/icons": "^3.31.0",
|
||||
"@tabler/icons-react": "^3.31.0",
|
||||
"axios": "^1.9.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-rnd": "^10.5.2",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { HomePage } from './pages/Home.page';
|
||||
import { Consulta_API } from './pages/Consulta_api';
|
||||
import { Error_404 } from './pages/404'; // Ajusta si está en otra carpeta
|
||||
import { Grid_Dashboard } from './pages/Grid_dashboard'; // Ajusta si está en otra carpeta
|
||||
import { Biblioteca } from './pages/Biblioteca';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -17,7 +18,10 @@ const router = createBrowserRouter([
|
||||
path: '/Grid_Dashboard',
|
||||
element: <Grid_Dashboard />,
|
||||
},
|
||||
|
||||
{
|
||||
path: '/Biblioteca',
|
||||
element: <Biblioteca />,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ export const submenuLinks = {
|
||||
Home: [
|
||||
{ label: 'Inicio', to: '/' },
|
||||
{ label: 'Consulta Api', to: '/Consulta_API' },
|
||||
{ label: 'Biblioteca', to: '/Biblioteca' },
|
||||
|
||||
],
|
||||
Dashboard: [
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
AppShell,
|
||||
Stack,
|
||||
Card,
|
||||
Text,
|
||||
Title,
|
||||
ScrollArea,
|
||||
Group,
|
||||
Button,
|
||||
TextInput,
|
||||
Modal,
|
||||
Box,
|
||||
Loader,
|
||||
} from '@mantine/core';
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import axios from 'axios';
|
||||
|
||||
type Nota = {
|
||||
id: string;
|
||||
titulo: string;
|
||||
texto: string;
|
||||
};
|
||||
|
||||
type Biblioteca = {
|
||||
id: string;
|
||||
nombre: string;
|
||||
descripcion: string;
|
||||
notas: Nota[];
|
||||
};
|
||||
|
||||
export function Biblioteca() {
|
||||
const [bibliotecas, setBibliotecas] = useState<Biblioteca[]>([]);
|
||||
const [bibliotecaSeleccionada, setBibliotecaSeleccionada] = useState<Biblioteca | null>(null);
|
||||
const [modalAbierto, setModalAbierto] = useState(false);
|
||||
const [tituloNota, setTituloNota] = useState('');
|
||||
const [contenidoNota, setContenidoNota] = useState('');
|
||||
const [loadingNotas, setLoadingNotas] = useState(false);
|
||||
|
||||
const fetchBibliotecas = async () => {
|
||||
try {
|
||||
const res = await axios.get('/api/v1/text_manager/list');
|
||||
console.log('📦 Respuesta del backend:', res.data);
|
||||
|
||||
if (!Array.isArray(res.data)) {
|
||||
console.error('❌ La respuesta no es un array:', res.data);
|
||||
return;
|
||||
}
|
||||
|
||||
const bibliotecasConNotas = await Promise.all(
|
||||
res.data.map(async (biblio: Omit<Biblioteca, 'notas'>) => {
|
||||
const notas = await axios.get(`/api/v1/text_manager/nota/list/${biblio.id}`);
|
||||
return { ...biblio, notas: notas.data as Nota[] };
|
||||
})
|
||||
);
|
||||
setBibliotecas(bibliotecasConNotas);
|
||||
setBibliotecaSeleccionada(bibliotecasConNotas[0] || null);
|
||||
} catch (error) {
|
||||
console.error('Error al cargar bibliotecas:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const agregarNota = async () => {
|
||||
if (!bibliotecaSeleccionada) return;
|
||||
|
||||
try {
|
||||
await axios.post(`/api/v1/text_manager/nota/${bibliotecaSeleccionada.id}`, {
|
||||
titulo: tituloNota,
|
||||
texto: contenidoNota,
|
||||
tags: [],
|
||||
conexiones: [],
|
||||
resumen: '',
|
||||
});
|
||||
|
||||
setLoadingNotas(true);
|
||||
const nuevasNotas = await axios.get(`/api/v1/text_manager/nota/list/${bibliotecaSeleccionada.id}`);
|
||||
const nuevasBibliotecas = bibliotecas.map((b) =>
|
||||
b.id === bibliotecaSeleccionada.id ? { ...b, notas: nuevasNotas.data as Nota[] } : b
|
||||
);
|
||||
setBibliotecas(nuevasBibliotecas);
|
||||
setBibliotecaSeleccionada(nuevasBibliotecas.find((b) => b.id === bibliotecaSeleccionada.id) || null);
|
||||
setTituloNota('');
|
||||
setContenidoNota('');
|
||||
setModalAbierto(false);
|
||||
} catch (error) {
|
||||
console.error('Error al agregar nota:', error);
|
||||
} finally {
|
||||
setLoadingNotas(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchBibliotecas();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AppShellWithMenu>
|
||||
<Box display="flex" h="100%">
|
||||
<Box w={240} p="md">
|
||||
<ScrollArea h="100%">
|
||||
<Stack>
|
||||
{bibliotecas.map((biblio) => (
|
||||
<Button
|
||||
key={biblio.id}
|
||||
size="xs"
|
||||
fullWidth
|
||||
variant={biblio.id === bibliotecaSeleccionada?.id ? 'filled' : 'light'}
|
||||
color="blue"
|
||||
onClick={() => setBibliotecaSeleccionada(biblio)}
|
||||
>
|
||||
{biblio.nombre}
|
||||
</Button>
|
||||
))}
|
||||
</Stack>
|
||||
</ScrollArea>
|
||||
</Box>
|
||||
|
||||
<Box p="md" style={{ flex: 1 }}>
|
||||
{bibliotecaSeleccionada ? (
|
||||
<Stack>
|
||||
<Title order={2}>{bibliotecaSeleccionada.nombre}</Title>
|
||||
<Group>
|
||||
<Button color="teal" onClick={fetchBibliotecas}>
|
||||
🔄 Recuperar bibliotecas
|
||||
</Button>
|
||||
<Button onClick={() => setModalAbierto(true)}>Agregar nota</Button>
|
||||
</Group>
|
||||
<Group>
|
||||
{loadingNotas ? (
|
||||
<Loader />
|
||||
) : (
|
||||
bibliotecaSeleccionada.notas.map((nota) => (
|
||||
<Card key={nota.id} shadow="sm" padding="lg" radius="md" withBorder style={{ width: 300 }}>
|
||||
<Title order={4}>{nota.titulo}</Title>
|
||||
<Text>{nota.texto}</Text>
|
||||
</Card>
|
||||
))
|
||||
)}
|
||||
</Group>
|
||||
</Stack>
|
||||
) : (
|
||||
<Stack>
|
||||
<Text>Selecciona una biblioteca</Text>
|
||||
<Button color="teal" onClick={fetchBibliotecas}>
|
||||
🔄 Recuperar bibliotecas
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Modal opened={modalAbierto} onClose={() => setModalAbierto(false)} title="Agregar nueva nota">
|
||||
<Stack>
|
||||
<TextInput
|
||||
label="Título"
|
||||
value={tituloNota}
|
||||
onChange={(event) => setTituloNota(event.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Contenido"
|
||||
value={contenidoNota}
|
||||
onChange={(event) => setContenidoNota(event.currentTarget.value)}
|
||||
/>
|
||||
<Button onClick={agregarNota}>Guardar</Button>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</AppShellWithMenu>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,15 @@ import svgr from 'vite-plugin-svgr';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tsconfigPaths(), svgr()],
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
|
||||
@@ -1224,6 +1224,11 @@ async-function@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz"
|
||||
integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
available-typed-arrays@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
|
||||
@@ -1236,6 +1241,15 @@ axe-core@^4.10.0:
|
||||
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz"
|
||||
integrity sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==
|
||||
|
||||
axios@^1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz"
|
||||
integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.6"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axobject-query@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz"
|
||||
@@ -1446,6 +1460,13 @@ colord@^2.9.3:
|
||||
resolved "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz"
|
||||
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
||||
@@ -1641,6 +1662,11 @@ define-properties@^1.1.3, define-properties@^1.2.1:
|
||||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
depd@^2.0.0, depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
|
||||
@@ -2273,6 +2299,11 @@ flatted@^3.2.9, flatted@^3.3.3:
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
||||
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
|
||||
|
||||
follow-redirects@^1.15.6:
|
||||
version "1.15.9"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz"
|
||||
integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
|
||||
|
||||
for-each@^0.3.3, for-each@^0.3.5:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz"
|
||||
@@ -2288,6 +2319,16 @@ foreground-child@^3.1.0:
|
||||
cross-spawn "^7.0.6"
|
||||
signal-exit "^4.0.1"
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz"
|
||||
integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
es-set-tostringtag "^2.1.0"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
|
||||
@@ -3162,6 +3203,18 @@ mime-db@^1.54.0:
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
|
||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime-types@^3.0.0, mime-types@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz"
|
||||
@@ -3586,6 +3639,11 @@ proxy-addr@^2.0.7:
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
punycode@^2.1.0, punycode@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
||||
|
||||
@@ -4,6 +4,8 @@ from typing import List, Optional
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from sqlalchemy import MetaData # Asegúrate de importar esto
|
||||
from src.TextManager.notas_biblioteca_mmr import generar_tabla_nota_para_biblioteca # Ajusta si es necesario
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
class Biblioteca:
|
||||
def __init__(
|
||||
@@ -24,7 +26,7 @@ class Biblioteca:
|
||||
:param vector_dim: Dimensión del vector si no se proporciona un embedder.
|
||||
"""
|
||||
self.id = id if id is not None else GeneradorIDUnico("BBLI").generar()
|
||||
self.nombre = nombre
|
||||
self.nombre = nombre if "biblio" in nombre else f"biblio_{nombre}"
|
||||
self.descripcion = descripcion
|
||||
self.embedder = embedder
|
||||
|
||||
@@ -38,14 +40,16 @@ class Biblioteca:
|
||||
def generar_modelo_notas(self, conexion: ConexionBase):
|
||||
"""
|
||||
Genera dinámicamente un modelo de notas asociado a esta biblioteca y lo crea en la base de datos.
|
||||
|
||||
:param conexion: Objeto de conexión a la base de datos.
|
||||
:return: Clase del modelo SQLAlchemy correspondiente a las notas.
|
||||
Previene la creación si la tabla ya existe.
|
||||
"""
|
||||
nombre_tabla = f"biblio_{self.nombre}"
|
||||
|
||||
metadata = MetaData()
|
||||
nombre_tabla = f"{self.nombre}"
|
||||
engine = conexion.get_engine()
|
||||
|
||||
inspector = inspect(engine)
|
||||
if inspector.has_table(nombre_tabla):
|
||||
raise ValueError(f"Ya existe una tabla con el nombre '{nombre_tabla}' en la base de datos.")
|
||||
|
||||
metadata = MetaData()
|
||||
tabla, NotaModel = generar_tabla_nota_para_biblioteca(nombre_tabla, self.vector_dim, metadata)
|
||||
metadata.create_all(engine)
|
||||
return NotaModel
|
||||
return NotaModel
|
||||
@@ -26,8 +26,8 @@ if pssword is None:
|
||||
class BibliotecaModel(Base):
|
||||
__tablename__ = "bibliotecas"
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
nombre = Column(String, nullable=False)
|
||||
id = Column(String, primary_key=True, unique=True)
|
||||
nombre = Column(String, nullable=False, unique=True)
|
||||
descripcion = Column(String, default="")
|
||||
vector_dim = Column(Integer, nullable=False)
|
||||
embedder_info = Column(String, nullable=True) # Se puede guardar nombre de clase o config encriptada
|
||||
@@ -77,6 +77,11 @@ class BibliotecaRepo:
|
||||
self.session = conexion.get_session()
|
||||
|
||||
def add(self, biblioteca: Biblioteca) -> str:
|
||||
# Verificar si ya existe una biblioteca con el mismo nombre
|
||||
existente = self.session.query(BibliotecaModel).filter_by(nombre=biblioteca.nombre).first()
|
||||
if existente:
|
||||
raise ValueError(f"Ya existe una biblioteca con el nombre '{biblioteca.nombre}'")
|
||||
|
||||
data = BibliotecaMapper.to_dict(biblioteca)
|
||||
model = BibliotecaModel(**data)
|
||||
self.session.add(model)
|
||||
|
||||
@@ -33,8 +33,8 @@ def generar_tabla_nota_para_biblioteca(biblioteca_nombre: str, vector_dim: int,
|
||||
Column("conexiones", String),
|
||||
Column("texto", String),
|
||||
Column("resumen", String),
|
||||
Column("vector", Vector(vector_dim), nullable=False),
|
||||
Column("vector_resumen", Vector(vector_dim), nullable=True), # AHORA ES OPCIONAL
|
||||
Column("vector", Vector(vector_dim), nullable=True),
|
||||
Column("vector_resumen", Vector(vector_dim), nullable=True),
|
||||
)
|
||||
|
||||
class NotaModel:
|
||||
@@ -46,9 +46,12 @@ def generar_tabla_nota_para_biblioteca(biblioteca_nombre: str, vector_dim: int,
|
||||
self.texto = nota.texto
|
||||
self.resumen = nota.resumen
|
||||
self.vector = nota.vector
|
||||
self.vector_resumen = getattr(nota, "vector_resumen", None) # AHORA ES OPCIONAL
|
||||
self.vector_resumen = getattr(nota, "vector_resumen", None)
|
||||
|
||||
# Evitar mapear dos veces la misma clase
|
||||
if NotaModel not in mapper_registry._class_registry.values():
|
||||
mapper_registry.map_imperatively(NotaModel, tabla)
|
||||
|
||||
mapper_registry.map_imperatively(NotaModel, tabla)
|
||||
return tabla, NotaModel
|
||||
|
||||
|
||||
@@ -79,7 +82,7 @@ class NotaMapper:
|
||||
conexiones=model.conexiones.split(",") if model.conexiones else [],
|
||||
texto=model.texto,
|
||||
resumen=model.resumen,
|
||||
vector=list(model.vector),
|
||||
vector=list(model.vector) if model.vector is not None else None,
|
||||
vector_resumen=list(model.vector_resumen) if model.vector_resumen is not None else None
|
||||
)
|
||||
|
||||
@@ -89,6 +92,8 @@ class NotaMapper:
|
||||
|
||||
class NotaRepo:
|
||||
def __init__(self, session: Session, modelo_nota):
|
||||
if modelo_nota is None:
|
||||
raise ValueError("No se puede instanciar NotaRepo sin un modelo válido de nota.")
|
||||
self.session = session
|
||||
self.ModeloNota = modelo_nota
|
||||
|
||||
|
||||
Reference in New Issue
Block a user