Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9db2f70009 | |||
| 95c1762ca7 | |||
| 6e716f8f98 | |||
| c13240b481 | |||
| bf1814bb8e | |||
| 712bd877b8 | |||
| b34d52036e | |||
| c47b9474f4 | |||
| c646bc1fef | |||
| f7879e9557 | |||
| 41b307f4bb | |||
| 1022e23a0d | |||
| 0d1ffcd1ff | |||
| b087271255 | |||
| 2becc8bc7c | |||
| 8d35da1972 | |||
| 20173e9042 | |||
| d45039e2f5 | |||
| 24fa4ada61 | |||
| b4ca0cf600 | |||
| 234639a34a | |||
| 9ab92c521a | |||
| 00fd103112 |
+11
@@ -12,3 +12,14 @@ wheels/
|
|||||||
# Volume mounts
|
# Volume mounts
|
||||||
data/postgresql/pgdata/*
|
data/postgresql/pgdata/*
|
||||||
pruebas_conceptos/postgres_extensions/pgdata/*
|
pruebas_conceptos/postgres_extensions/pgdata/*
|
||||||
|
|
||||||
|
# Local configuration files
|
||||||
|
*.env
|
||||||
|
config/.env
|
||||||
|
|
||||||
|
|
||||||
|
#Icon files
|
||||||
|
frontend/src/assets/icons/filled/** */
|
||||||
|
frontend/src/assets/icons/outlined/** */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# backend/api/endpoints/ping.py
|
||||||
|
|
||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
async def ping():
|
||||||
|
return {"message": "pong"}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from fastapi import Path
|
||||||
|
|
||||||
|
from backend.schemas.text_manager_schema import BibliotecaInput, NotaInput
|
||||||
|
|
||||||
|
from fastapi.concurrency import run_in_threadpool
|
||||||
|
from backend.db.conexion import get_conexion
|
||||||
|
from backend.services.text_manager_srvc import *
|
||||||
|
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/biblioteca", summary="Crear una nueva biblioteca")
|
||||||
|
async def crear_biblioteca_endpoint(
|
||||||
|
data: BibliotecaInput,
|
||||||
|
conexion: PostgresConexion = Depends(get_conexion)
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return await run_in_threadpool(
|
||||||
|
crear_biblioteca,
|
||||||
|
data.nombre_biblioteca,
|
||||||
|
conexion,
|
||||||
|
data.descripcion,
|
||||||
|
)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=404, detail=str(e))
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error interno al crear la biblioteca: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/nota/{biblioteca_id}/{nota_id}", summary="Eliminar una nota por ID")
|
||||||
|
def eliminar_nota_endpoint(
|
||||||
|
biblioteca_id: str = Path(..., description="ID de la biblioteca"),
|
||||||
|
nota_id: str = Path(..., description="ID de la nota a eliminar"),
|
||||||
|
conexion: PostgresConexion = Depends(get_conexion)
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return eliminar_nota(conexion=conexion, biblioteca_id=biblioteca_id, nota_id=nota_id)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=404, detail=str(e))
|
||||||
|
except Exception:
|
||||||
|
raise HTTPException(status_code=500, detail="Error interno al eliminar la nota")
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/nota/{biblioteca_id}/{nota_id}", summary="Actualizar una nota por ID")
|
||||||
|
def actualizar_nota_endpoint(
|
||||||
|
biblioteca_id: str = Path(..., description="ID de la biblioteca"),
|
||||||
|
nota_id: str = Path(..., description="ID de la nota a actualizar"),
|
||||||
|
nota: NotaInput = ..., # body
|
||||||
|
conexion: PostgresConexion = Depends(get_conexion)
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
return actualizar_nota(conexion=conexion, biblioteca_id=biblioteca_id, nota_id=nota_id, nota_input=nota)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=404, detail=str(e))
|
||||||
|
except Exception:
|
||||||
|
raise HTTPException(status_code=500, detail="Error interno al actualizar la nota")
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# backend/api/router.py
|
||||||
|
|
||||||
|
from fastapi import APIRouter
|
||||||
|
from backend.api.v1.endpoints import ping, text_manager_endpoint
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
router.include_router(ping.router, prefix="/api/v1/ping")
|
||||||
|
router.include_router(text_manager_endpoint.router, prefix="/api/v1/text_manager")
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# backend/db/conexion.py
|
||||||
|
from entrypoint.init_db import db_credencial
|
||||||
|
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||||
|
|
||||||
|
def get_conexion():
|
||||||
|
conexion = PostgresConexion(db_credencial)
|
||||||
|
try:
|
||||||
|
yield conexion
|
||||||
|
finally:
|
||||||
|
conexion.close()
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# backend/main.py
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from backend.api.v1.router import router
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="Fitz Backend",
|
||||||
|
description="API para interacción con el frontend y ejecución de tareas",
|
||||||
|
version="0.1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configuración de CORS
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["http://localhost:5173", "http://0.0.0.0:5173"], # Solo permite tu frontend local
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Incluye las rutas de tu API
|
||||||
|
app.include_router(router)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
|
||||||
|
class NotaInput(BaseModel):
|
||||||
|
titulo: str
|
||||||
|
texto: str = ""
|
||||||
|
tags: Optional[List[str]] = []
|
||||||
|
conexiones: Optional[List[str]] = []
|
||||||
|
resumen: Optional[str] = ""
|
||||||
|
|
||||||
|
|
||||||
|
class BibliotecaInput(BaseModel):
|
||||||
|
nombre_biblioteca: str
|
||||||
|
descripcion: str
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
from src.TextManager.biblioteca import Biblioteca
|
||||||
|
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 src.TextManager.nota import Nota
|
||||||
|
from src.TextManager.notas_mmr import generar_tabla_nota_para_biblioteca, NotaRepo
|
||||||
|
from sqlalchemy import MetaData
|
||||||
|
from backend.schemas.text_manager_schema import NotaInput
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def crear_biblioteca(nombre_biblioteca: str, conexion: PostgresConexion, descripcion: str = None):
|
||||||
|
print("[INICIO] Creando biblioteca...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("[Paso 1] Obteniendo credencial...")
|
||||||
|
cred_repo = OpenAICredencialRepo(conexion)
|
||||||
|
credencial = cred_repo.get_by_id("OPAK20250513-61b29978b7604031014")
|
||||||
|
print("[OK] Credencial obtenida:", credencial.titulo if credencial else "❌ None")
|
||||||
|
|
||||||
|
print("[Paso 2] Instanciando embedder...")
|
||||||
|
embedder = OpenAIEmbedder(credencial, model="text-embedding-3-large")
|
||||||
|
print("[OK] Embedder instanciado")
|
||||||
|
|
||||||
|
print("[Paso 3] Instanciando biblioteca...")
|
||||||
|
biblioteca = Biblioteca(
|
||||||
|
nombre=nombre_biblioteca,
|
||||||
|
embedder=embedder,
|
||||||
|
descripcion=descripcion
|
||||||
|
)
|
||||||
|
print(f"[OK] Biblioteca instanciada con ID: {biblioteca.id}")
|
||||||
|
|
||||||
|
print("[Paso 4] Guardando en base de datos...")
|
||||||
|
repo = BibliotecaRepo(conexion)
|
||||||
|
repo.add(biblioteca=biblioteca)
|
||||||
|
print("[OK] Biblioteca guardada")
|
||||||
|
|
||||||
|
print("[Paso 5] Generando modelo de notas...")
|
||||||
|
biblioteca.generar_modelo_notas(conexion)
|
||||||
|
print("[OK] Modelo de notas generado")
|
||||||
|
|
||||||
|
print("[FIN] Biblioteca creada correctamente")
|
||||||
|
return {
|
||||||
|
"mensaje": f"Biblioteca '{nombre_biblioteca}' creada con éxito.",
|
||||||
|
"id": biblioteca.id
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("[ERROR] Ocurrió una excepción:", str(e))
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
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 = ""
|
||||||
|
):
|
||||||
|
|
||||||
|
# Obtener la biblioteca
|
||||||
|
repo_biblioteca = BibliotecaRepo(conexion)
|
||||||
|
biblioteca = repo_biblioteca.get_by_id(biblioteca_id)
|
||||||
|
if biblioteca is None:
|
||||||
|
raise ValueError(f"No se encontró la biblioteca con ID {biblioteca_id}")
|
||||||
|
|
||||||
|
# Crear objeto Nota
|
||||||
|
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
|
||||||
|
metadata = MetaData()
|
||||||
|
tabla, ModeloNota = generar_tabla_nota_para_biblioteca(
|
||||||
|
biblioteca.nombre,
|
||||||
|
biblioteca.vector_dim,
|
||||||
|
metadata
|
||||||
|
)
|
||||||
|
metadata.create_all(conexion.get_engine())
|
||||||
|
|
||||||
|
# Guardar la nota
|
||||||
|
repo_nota = NotaRepo(conexion.get_session(), ModeloNota)
|
||||||
|
nota_id = repo_nota.add(nota)
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def eliminar_nota(conexion: PostgresConexion, biblioteca_id: str, nota_id: str) -> 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()
|
||||||
|
_, 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)
|
||||||
|
fue_eliminada = repo_nota.delete_by_id(nota_id)
|
||||||
|
|
||||||
|
if fue_eliminada:
|
||||||
|
return {"mensaje": f"Nota '{nota_id}' eliminada correctamente."}
|
||||||
|
else:
|
||||||
|
raise ValueError(f"No se encontró la nota con ID: {nota_id}")
|
||||||
|
|
||||||
|
|
||||||
|
def actualizar_nota(conexion: PostgresConexion, biblioteca_id: str, nota_id: str, nota_input: NotaInput) -> 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()
|
||||||
|
_, 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)
|
||||||
|
nota_actualizada = Nota(
|
||||||
|
titulo=nota_input.titulo,
|
||||||
|
texto=nota_input.texto,
|
||||||
|
tags=nota_input.tags or [],
|
||||||
|
conexiones=nota_input.conexiones or [],
|
||||||
|
resumen=nota_input.resumen or ""
|
||||||
|
)
|
||||||
|
fue_actualizada = repo_nota.update(nota_id, nota_actualizada)
|
||||||
|
|
||||||
|
if fue_actualizada:
|
||||||
|
return {"mensaje": f"Nota '{nota_id}' actualizada correctamente."}
|
||||||
|
else:
|
||||||
|
raise ValueError(f"No se encontró la nota con ID: {nota_id}")
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def eliminar_pycache(directorio):
|
||||||
|
eliminados = 0
|
||||||
|
for root, dirs, files in os.walk(directorio):
|
||||||
|
for d in dirs:
|
||||||
|
if d == "__pycache__":
|
||||||
|
ruta = os.path.join(root, d)
|
||||||
|
print(f"🗑️ Eliminando: {ruta}")
|
||||||
|
shutil.rmtree(ruta)
|
||||||
|
eliminados += 1
|
||||||
|
print(f"\n✅ Eliminados {eliminados} directorios '__pycache__'.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
ruta_raiz = os.path.dirname(os.path.abspath(__file__)) # Carpeta actual
|
||||||
|
eliminar_pycache(ruta_raiz)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import asyncio
|
||||||
|
from fastmcp.client import Client
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with Client("http://127.0.0.1:4300") as client:
|
||||||
|
is_alive = await client.ping()
|
||||||
|
print("Ping exitoso:", is_alive)
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
# Tipo de base de datos
|
|
||||||
DB_TITLE=Production_Fitz_db
|
|
||||||
DB_USER=postgres
|
|
||||||
DB_PASSWORD=7Souw9SFD5P5RYpRWuTVvFkY7zlxATcN
|
|
||||||
DB_HOST=localhost
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_NAME=fitz_db
|
|
||||||
|
|
||||||
|
|
||||||
# Contraseña maestra de la aplicacion
|
|
||||||
MASTER_PASSWORD=¤òAíÀÇ®8IgÄËïºÅ2a3duÎ4Ô¯5¦ï¤ç··sôÃmL9xWß
|
|
||||||
|
|
||||||
#Ruta del proyecto
|
|
||||||
PROJECT_PATH= E:\Fitz_Studio
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Tipo de base de datos
|
||||||
|
DB_TITLE=
|
||||||
|
DB_USER=
|
||||||
|
DB_PASSWORD=
|
||||||
|
DB_HOST=
|
||||||
|
DB_PORT=
|
||||||
|
DB_NAME=
|
||||||
|
|
||||||
|
|
||||||
|
# Contraseña maestra de la aplicacion
|
||||||
|
MASTER_PASSWORD=
|
||||||
|
|
||||||
|
#Ruta del proyecto
|
||||||
|
PROJECT_PATH=
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,10 @@ from src.Credenciales.postgres_credencial import PostgresCredencial # Asegúrat
|
|||||||
|
|
||||||
from src.Credenciales.postgres_credencial_mmr import PostgresCredencialModel
|
from src.Credenciales.postgres_credencial_mmr import PostgresCredencialModel
|
||||||
from src.ApiKeys.openai_apikey_mmr import OpenAICredencialModel
|
from src.ApiKeys.openai_apikey_mmr import OpenAICredencialModel
|
||||||
from llms.Modelos.Openai_model_mmr import ModeloOpenAIConfigModel
|
from src.Llms.Modelos.Openai_model_mmr import ModeloOpenAIConfigModel
|
||||||
|
from src.Llms.Embedders.Openai_embedder_mmr import OpenAIEmbedderModel
|
||||||
|
from src.TextManager.biblioteca_mmr import BibliotecaModel
|
||||||
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import os
|
import os
|
||||||
@@ -41,7 +44,7 @@ def init_db():
|
|||||||
|
|
||||||
# Crear engine desde la clase de conexión PostgreSQL
|
# Crear engine desde la clase de conexión PostgreSQL
|
||||||
conexion = PostgresConexion(db_credencial)
|
conexion = PostgresConexion(db_credencial)
|
||||||
engine = conexion.engine # Recuperamos el engine directamente
|
engine = conexion.get_engine() # Recuperamos el engine directamente
|
||||||
|
|
||||||
print("Creando tablas...")
|
print("Creando tablas...")
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ yarn-error.log*
|
|||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
src/assets/icons/filled/*
|
||||||
|
src/assets/icons/outlined/*
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -2,12 +2,12 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="src/assets/icons/favicon.svg" />
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
||||||
/>
|
/>
|
||||||
<title>Vite + Mantine App</title>
|
<title>FitzStudio</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
Generated
+560
-19
@@ -11,9 +11,12 @@
|
|||||||
"@mantine/core": "8.0.0",
|
"@mantine/core": "8.0.0",
|
||||||
"@mantine/hooks": "8.0.0",
|
"@mantine/hooks": "8.0.0",
|
||||||
"@react-three/fiber": "^9.1.2",
|
"@react-three/fiber": "^9.1.2",
|
||||||
|
"@tabler/icons": "^3.31.0",
|
||||||
"@tabler/icons-react": "^3.31.0",
|
"@tabler/icons-react": "^3.31.0",
|
||||||
|
"axios": "^1.9.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
"react-rnd": "^10.5.2",
|
||||||
"react-router-dom": "^7.4.0"
|
"react-router-dom": "^7.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -28,6 +31,7 @@
|
|||||||
"@types/node": "^22.13.11",
|
"@types/node": "^22.13.11",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"@types/three": "^0.176.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-config-mantine": "^4.0.3",
|
"eslint-config-mantine": "^4.0.3",
|
||||||
@@ -47,6 +51,7 @@
|
|||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.27.0",
|
"typescript-eslint": "^8.27.0",
|
||||||
"vite": "^6.2.2",
|
"vite": "^6.2.2",
|
||||||
|
"vite-plugin-svgr": "^4.3.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^3.0.9"
|
"vitest": "^3.0.9"
|
||||||
}
|
}
|
||||||
@@ -533,6 +538,13 @@
|
|||||||
"@csstools/css-tokenizer": "^3.0.3"
|
"@csstools/css-tokenizer": "^3.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dimforge/rapier3d-compat": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@dual-bundle/import-meta-resolve": {
|
"node_modules/@dual-bundle/import-meta-resolve": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
||||||
@@ -2085,6 +2097,271 @@
|
|||||||
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
|
"storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-remove-jsx-attribute": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-svg-dynamic-title": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-svg-em-dimensions": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-transform-react-native-svg": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-plugin-transform-svg-component": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/babel-preset": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@svgr/babel-plugin-add-jsx-attribute": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-remove-jsx-attribute": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-svg-dynamic-title": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-svg-em-dimensions": "8.0.0",
|
||||||
|
"@svgr/babel-plugin-transform-react-native-svg": "8.1.0",
|
||||||
|
"@svgr/babel-plugin-transform-svg-component": "8.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/core": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.21.3",
|
||||||
|
"@svgr/babel-preset": "8.1.0",
|
||||||
|
"camelcase": "^6.2.0",
|
||||||
|
"cosmiconfig": "^8.1.3",
|
||||||
|
"snake-case": "^3.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/core/node_modules/cosmiconfig": {
|
||||||
|
"version": "8.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
|
||||||
|
"integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"import-fresh": "^3.3.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"parse-json": "^5.2.0",
|
||||||
|
"path-type": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/d-fischer"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.9.5"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/hast-util-to-babel-ast": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/types": "^7.21.3",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@svgr/plugin-jsx": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.21.3",
|
||||||
|
"@svgr/babel-preset": "8.1.0",
|
||||||
|
"@svgr/hast-util-to-babel-ast": "8.0.0",
|
||||||
|
"svg-parser": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/gregberge"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@svgr/core": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tabler/icons": {
|
"node_modules/@tabler/icons": {
|
||||||
"version": "3.31.0",
|
"version": "3.31.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz",
|
||||||
@@ -2215,6 +2492,13 @@
|
|||||||
"@testing-library/dom": ">=7.21.4"
|
"@testing-library/dom": ">=7.21.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tweenjs/tween.js": {
|
||||||
|
"version": "23.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
|
||||||
|
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/aria-query": {
|
"node_modules/@types/aria-query": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
@@ -2333,6 +2617,29 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/stats.js": {
|
||||||
|
"version": "0.17.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
|
||||||
|
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/three": {
|
||||||
|
"version": "0.176.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz",
|
||||||
|
"integrity": "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@dimforge/rapier3d-compat": "^0.12.0",
|
||||||
|
"@tweenjs/tween.js": "~23.1.3",
|
||||||
|
"@types/stats.js": "*",
|
||||||
|
"@types/webxr": "*",
|
||||||
|
"@webgpu/types": "*",
|
||||||
|
"fflate": "~0.8.2",
|
||||||
|
"meshoptimizer": "~0.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/webxr": {
|
"node_modules/@types/webxr": {
|
||||||
"version": "0.5.22",
|
"version": "0.5.22",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
|
||||||
@@ -2688,6 +2995,13 @@
|
|||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@webgpu/types": {
|
||||||
|
"version": "0.1.60",
|
||||||
|
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz",
|
||||||
|
"integrity": "sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||||
@@ -2991,6 +3305,12 @@
|
|||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/available-typed-arrays": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
@@ -3017,6 +3337,17 @@
|
|||||||
"node": ">=4"
|
"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": {
|
"node_modules/axobject-query": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||||
@@ -3239,7 +3570,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@@ -3276,6 +3606,19 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelcase": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/camelcase-css": {
|
"node_modules/camelcase-css": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
@@ -3387,6 +3730,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@@ -3727,6 +4082,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@@ -3786,11 +4150,21 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/dot-case": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"no-case": "^3.0.4",
|
||||||
|
"tslib": "^2.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.1",
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
@@ -3942,7 +4316,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -3952,7 +4325,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -3997,7 +4369,6 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0"
|
"es-errors": "^1.3.0"
|
||||||
@@ -4010,7 +4381,6 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@@ -4635,6 +5005,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||||
@@ -4717,6 +5094,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||||
@@ -4750,6 +5147,42 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"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": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
@@ -4789,7 +5222,6 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@@ -4840,7 +5272,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.2",
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
@@ -4874,7 +5305,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dunder-proto": "^1.0.1",
|
"dunder-proto": "^1.0.1",
|
||||||
@@ -5069,7 +5499,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -5148,7 +5577,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -5161,7 +5589,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
@@ -5177,7 +5604,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
@@ -5925,7 +6351,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
@@ -6170,7 +6595,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
@@ -6186,6 +6610,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lower-case": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -6227,7 +6661,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -6307,6 +6740,13 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/meshoptimizer": {
|
||||||
|
"version": "0.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
|
||||||
|
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
@@ -6443,6 +6883,17 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/no-case": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lower-case": "^2.0.2",
|
||||||
|
"tslib": "^2.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.19",
|
"version": "2.0.19",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||||
@@ -6471,7 +6922,6 @@
|
|||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -7160,7 +7610,6 @@
|
|||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
@@ -7172,7 +7621,6 @@
|
|||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
@@ -7189,6 +7637,12 @@
|
|||||||
"node": ">= 0.10"
|
"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": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
@@ -7262,6 +7716,16 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/re-resizable": {
|
||||||
|
"version": "6.11.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.11.2.tgz",
|
||||||
|
"integrity": "sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "19.1.0",
|
"version": "19.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
@@ -7328,6 +7792,29 @@
|
|||||||
"react": "^19.1.0"
|
"react": "^19.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-draggable": {
|
||||||
|
"version": "4.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz",
|
||||||
|
"integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^1.1.1",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.3.0",
|
||||||
|
"react-dom": ">= 16.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-draggable/node_modules/clsx": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@@ -7423,6 +7910,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-rnd": {
|
||||||
|
"version": "10.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-rnd/-/react-rnd-10.5.2.tgz",
|
||||||
|
"integrity": "sha512-0Tm4x7k7pfHf2snewJA8x7Nwgt3LV+58MVEWOVsFjk51eYruFEa6Wy7BNdxt4/lH0wIRsu7Gm3KjSXY2w7YaNw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"re-resizable": "6.11.2",
|
||||||
|
"react-draggable": "4.4.6",
|
||||||
|
"tslib": "2.6.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.3.0",
|
||||||
|
"react-dom": ">=16.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-rnd/node_modules/tslib": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.5.3",
|
"version": "7.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.3.tgz",
|
||||||
@@ -8116,6 +8624,17 @@
|
|||||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/snake-case": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dot-case": "^3.0.4",
|
||||||
|
"tslib": "^2.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
@@ -8846,6 +9365,13 @@
|
|||||||
"react": ">=17.0"
|
"react": ">=17.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svg-parser": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/svg-tags": {
|
"node_modules/svg-tags": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
||||||
@@ -9628,6 +10154,21 @@
|
|||||||
"url": "https://opencollective.com/vitest"
|
"url": "https://opencollective.com/vitest"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-plugin-svgr": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@rollup/pluginutils": "^5.1.3",
|
||||||
|
"@svgr/core": "^8.1.0",
|
||||||
|
"@svgr/plugin-jsx": "^8.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": ">=2.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite-tsconfig-paths": {
|
"node_modules/vite-tsconfig-paths": {
|
||||||
"version": "5.1.4",
|
"version": "5.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz",
|
||||||
|
|||||||
@@ -23,9 +23,12 @@
|
|||||||
"@mantine/core": "8.0.0",
|
"@mantine/core": "8.0.0",
|
||||||
"@mantine/hooks": "8.0.0",
|
"@mantine/hooks": "8.0.0",
|
||||||
"@react-three/fiber": "^9.1.2",
|
"@react-three/fiber": "^9.1.2",
|
||||||
|
"@tabler/icons": "^3.31.0",
|
||||||
"@tabler/icons-react": "^3.31.0",
|
"@tabler/icons-react": "^3.31.0",
|
||||||
|
"axios": "^1.9.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
|
"react-rnd": "^10.5.2",
|
||||||
"react-router-dom": "^7.4.0"
|
"react-router-dom": "^7.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -40,6 +43,7 @@
|
|||||||
"@types/node": "^22.13.11",
|
"@types/node": "^22.13.11",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
|
"@types/three": "^0.176.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-config-mantine": "^4.0.3",
|
"eslint-config-mantine": "^4.0.3",
|
||||||
@@ -59,6 +63,7 @@
|
|||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.27.0",
|
"typescript-eslint": "^8.27.0",
|
||||||
"vite": "^6.2.2",
|
"vite": "^6.2.2",
|
||||||
|
"vite-plugin-svgr": "^4.3.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^3.0.9"
|
"vitest": "^3.0.9"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|||||||
import { HomePage } from './pages/Home.page';
|
import { HomePage } from './pages/Home.page';
|
||||||
import { Consulta_API } from './pages/Consulta_api';
|
import { Consulta_API } from './pages/Consulta_api';
|
||||||
import { Error_404 } from './pages/404'; // Ajusta si está en otra carpeta
|
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([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -12,6 +14,16 @@ const router = createBrowserRouter([
|
|||||||
path: '/Consulta_API',
|
path: '/Consulta_API',
|
||||||
element: <Consulta_API />,
|
element: <Consulta_API />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/Grid_Dashboard',
|
||||||
|
element: <Grid_Dashboard />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/Biblioteca',
|
||||||
|
element: <Biblioteca />,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
element: <Error_404 />,
|
element: <Error_404 />,
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="185.21428mm"
|
||||||
|
height="185.21428mm"
|
||||||
|
viewBox="0 0 185.21428 185.21428"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="favicon.svg"
|
||||||
|
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#242424"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="0.52284039"
|
||||||
|
inkscape:cx="317.49651"
|
||||||
|
inkscape:cy="284.02549"
|
||||||
|
inkscape:window-width="1147"
|
||||||
|
inkscape:window-height="927"
|
||||||
|
inkscape:window-x="2024"
|
||||||
|
inkscape:window-y="105"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-13.15728,-55.159447)">
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff"
|
||||||
|
id="path1"
|
||||||
|
cx="105.76442"
|
||||||
|
cy="147.76659"
|
||||||
|
r="92.60714" />
|
||||||
|
<path
|
||||||
|
d="m 60.52824,130.59648 q 5.092664,-3.88488 12.125369,-6.43431 7.032718,-2.54944 15.035463,-4.12768 2.78883,-3.52067 5.45641,-6.91992 2.66758,-3.52066 4.60763,-6.55571 1.94007,-3.15645 3.031358,-5.82731 1.09128,-2.792247 0.84876,-4.977477 l 0.24252,0.2428 q -0.60628,-1.21402 -2.910088,-1.82102 -2.30382,-0.72842 -5.45642,-0.72842 -4.00138,0 -8.972768,1.09262 -4.971406,0.97121 -10.064057,2.91365 -5.092651,1.82102 -10.064057,4.491867 -4.850147,2.67085 -8.851513,5.94871 -3.880108,3.27786 -6.547698,7.16273 -2.546319,3.88487 -2.910081,8.13394 -5.456413,-4.61327 -7.881486,-8.49814 -2.303829,-4.00627 -2.303829,-7.52694 0,-6.19151 3.152597,-10.926187 3.152597,-4.73468 8.124003,-8.13393 5.092651,-3.52067 11.519091,-5.827315 6.547698,-2.306631 13.095396,-3.642054 6.668943,-1.456837 12.852879,-1.94244 6.305193,-0.607005 10.912843,-0.607005 6.911448,0 12.974128,0.971207 6.06269,0.971221 10.54908,3.035062 4.60766,1.942428 7.27523,4.856075 2.66758,2.91365 2.66758,6.91992 -0.72751,3.88487 -2.54632,7.16272 -1.69755,3.277867 -3.88013,6.312907 -2.18257,2.91365 -4.60766,5.94871 -2.30381,2.91365 -4.24387,5.94871 2.78884,0.12142 5.09265,0.36421 2.42508,0.12141 4.72891,0.12141 l -5.33517,13.35423 q -3.27384,0 -5.33517,0 -2.0613,0 -3.6376,0.12142 -1.45505,0 -2.78884,0.12141 -1.21253,0.12141 -2.78884,0.3642 -0.2425,0 -0.36376,0.12142 -0.12128,0 -0.36376,0 -8.730248,12.86862 -13.944158,27.19407 -5.213911,14.20405 -7.881489,28.77232 -4.728902,0.2428 -8.972771,-0.36422 -4.122624,-0.4856 -7.153976,-2.06382 -2.910081,-1.45683 -4.365128,-4.00627 -1.455047,-2.54946 -0.727524,-6.31292 0.848782,-3.27786 2.425074,-7.76973 1.697551,-4.61329 3.637617,-9.59078 2.061313,-5.09889 4.24387,-10.19778 2.303828,-5.22029 4.486386,-9.71218 -3.031339,1.33543 -6.91146,3.15647 -3.880108,1.82102 -6.668943,3.64206 z m 103.06565,44.5546 q 0.24249,3.64205 -1.94006,8.49814 -2.18258,4.8561 -5.69893,10.07639 -3.3951,5.22029 -7.63897,10.31916 -4.24389,5.2203 -8.12401,9.46937 -3.8801,4.24907 -6.91144,7.04132 -3.03134,2.91365 -4.12263,3.52066 -1.57629,0.60702 -3.27384,1.09263 -1.57629,0.607 -3.88013,-0.36422 -1.45506,-0.60699 -3.51638,-1.69963 -1.94005,-0.97122 -3.6376,-2.42803 -1.8188,-1.33542 -2.78884,-3.15646 -1.09128,-1.69963 -0.60626,-3.76347 0.48502,-1.82104 2.30383,-4.49187 1.69755,-2.67085 4.12261,-5.70591 2.54633,-3.03505 5.57768,-6.1915 3.15261,-3.03505 6.3052,-5.82729 3.27385,-2.79225 6.3052,-4.85609 3.15258,-2.06384 5.82015,-3.03506 0.36376,-0.12142 0.72754,-1.82103 0.36375,-1.69964 0.12115,-4.49187 -0.12115,-1.45684 -0.72752,-3.15646 -0.48502,-1.69963 -1.45505,-3.03505 -0.84876,-1.33543 -2.18254,-2.18525 -1.3338,-0.97122 -2.91009,-0.97122 -2.78884,0 -5.82018,2.91365 -3.03134,2.54946 -5.57767,1.82104 -2.4251,-0.72842 -3.7589,-3.03506 -1.21252,-2.42803 -0.84877,-5.46309 0.48502,-3.03505 3.39511,-5.09889 0.97004,-0.60702 4.00138,-3.03505 3.03135,-2.54945 6.66897,-5.7059 3.63759,-3.15646 7.03269,-6.31292 3.39512,-3.27785 5.09267,-5.3417 1.57629,-1.94242 2.0613,-3.03504 0.48502,-1.09261 0.36376,-1.69963 -0.12116,-0.60702 -0.72752,-0.72842 -0.48502,-0.2428 -0.84877,-0.2428 -1.45505,-0.12141 -3.3951,-0.2428 -1.81881,-0.12142 -3.51636,0 -1.69754,0.12128 -3.15259,0.4856 -1.33379,0.2428 -1.81881,0.72842 -0.97002,0.7284 -3.03134,3.88487 -1.94005,3.03505 -4.24386,6.67711 -2.30383,3.64207 -4.48642,7.04132 -2.06132,3.39927 -3.03135,4.85609 -2.18257,3.03505 -4.36511,3.88487 -2.30382,0.72842 -3.88012,0 -1.57631,-0.72841 -1.94007,-2.54945 -0.48501,-1.82102 0.84878,-4.00627 1.45505,-2.30664 3.1526,-5.34169 1.69754,-3.15646 3.51636,-6.55571 1.81878,-3.52067 3.63759,-7.16274 1.94008,-3.64206 3.75889,-7.16273 1.3338,-2.42803 2.78885,-3.88487 1.45503,-1.57822 3.8801,-2.42803 2.9101,-0.72842 6.42644,-0.97122 3.63761,-0.24281 7.15397,-0.12141 3.51636,0 6.66895,0.3642 3.15259,0.2428 5.2139,0.36422 2.30381,0.24279 4.48638,1.94243 2.30383,1.69962 3.88013,3.88485 1.69755,2.18524 2.42507,4.6133 0.72752,2.30664 -0.12116,3.88486 -0.12115,0.24281 -1.45503,1.57823 -1.33379,1.33543 -3.51636,3.39927 -2.06131,2.06383 -4.7289,4.61327 -2.66758,2.42805 -5.33516,4.97749 -2.54633,2.42805 -4.9714,4.61329 -2.42506,2.18523 -4.00137,3.64205 h 1.45505 q 4.60763,0 7.88149,0.72842 3.39511,0.607 6.54769,3.27785 2.66758,-3.03505 5.57768,-7.52693 2.91008,-4.61328 5.45641,-8.74095 2.30381,-4.00628 4.60764,-5.22029 2.42506,-1.21402 4.12263,-0.60702 1.81879,0.48561 2.42507,2.54946 0.72751,1.94243 -0.36376,4.49186 -6.79022,11.0476 -11.15534,18.21033 -4.24387,7.04132 -6.30518,9.95498 z"
|
||||||
|
id="text1-8-5-1"
|
||||||
|
style="fill:#000000"
|
||||||
|
aria-label="Fz"
|
||||||
|
inkscape:label="text1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.9 KiB |
@@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type LogoIconProps = React.SVGProps<SVGSVGElement> & {
|
||||||
|
circleFill?: string;
|
||||||
|
pathFill?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LogoIcon: React.FC<LogoIconProps> = ({
|
||||||
|
style,
|
||||||
|
circleFill = 'currentColor',
|
||||||
|
pathFill = 'currentColor',
|
||||||
|
...props
|
||||||
|
}) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="1em"
|
||||||
|
height="1em"
|
||||||
|
viewBox="0 0 185.21428 185.21428"
|
||||||
|
style={style}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<g transform="translate(-13.15728,-55.159447)">
|
||||||
|
<circle
|
||||||
|
cx="105.76442"
|
||||||
|
cy="147.76659"
|
||||||
|
r="92.60714"
|
||||||
|
fill={circleFill}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="m 60.52824,130.59648 q 5.092664,-3.88488 12.125369,-6.43431 7.032718,-2.54944 15.035463,-4.12768 2.78883,-3.52067 5.45641,-6.91992 2.66758,-3.52066 4.60763,-6.55571 1.94007,-3.15645 3.031358,-5.82731 1.09128,-2.792247 0.84876,-4.977477 l 0.24252,0.2428 q -0.60628,-1.21402 -2.910088,-1.82102 -2.30382,-0.72842 -5.45642,-0.72842 -4.00138,0 -8.972768,1.09262 -4.971406,0.97121 -10.064057,2.91365 -5.092651,1.82102 -10.064057,4.491867 -4.850147,2.67085 -8.851513,5.94871 -3.880108,3.27786 -6.547698,7.16273 -2.546319,3.88487 -2.910081,8.13394 -5.456413,-4.61327 -7.881486,-8.49814 -2.303829,-4.00627 -2.303829,-7.52694 0,-6.19151 3.152597,-10.926187 3.152597,-4.73468 8.124003,-8.13393 5.092651,-3.52067 11.519091,-5.827315 6.547698,-2.306631 13.095396,-3.642054 6.668943,-1.456837 12.852879,-1.94244 6.305193,-0.607005 10.912843,-0.607005 6.911448,0 12.974128,0.971207 6.06269,0.971221 10.54908,3.035062 4.60766,1.942428 7.27523,4.856075 2.66758,2.91365 2.66758,6.91992 -0.72751,3.88487 -2.54632,7.16272 -1.69755,3.277867 -3.88013,6.312907 -2.18257,2.91365 -4.60766,5.94871 -2.30381,2.91365 -4.24387,5.94871 2.78884,0.12142 5.09265,0.36421 2.42508,0.12141 4.72891,0.12141 l -5.33517,13.35423 q -3.27384,0 -5.33517,0 -2.0613,0 -3.6376,0.12142 -1.45505,0 -2.78884,0.12141 -1.21253,0.12141 -2.78884,0.3642 -0.2425,0 -0.36376,0.12142 -0.12128,0 -0.36376,0 -8.730248,12.86862 -13.944158,27.19407 -5.213911,14.20405 -7.881489,28.77232 -4.728902,0.2428 -8.972771,-0.36422 -4.122624,-0.4856 -7.153976,-2.06382 -2.910081,-1.45683 -4.365128,-4.00627 -1.455047,-2.54946 -0.727524,-6.31292 0.848782,-3.27786 2.425074,-7.76973 1.697551,-4.61329 3.637617,-9.59078 2.061313,-5.09889 4.24387,-10.19778 2.303828,-5.22029 4.486386,-9.71218 -3.031339,1.33543 -6.91146,3.15647 -3.880108,1.82102 -6.668943,3.64206 z m 103.06565,44.5546 q 0.24249,3.64205 -1.94006,8.49814 -2.18258,4.8561 -5.69893,10.07639 -3.3951,5.22029 -7.63897,10.31916 -4.24389,5.2203 -8.12401,9.46937 -3.8801,4.24907 -6.91144,7.04132 -3.03134,2.91365 -4.12263,3.52066 -1.57629,0.60702 -3.27384,1.09263 -1.57629,0.607 -3.88013,-0.36422 -1.45506,-0.60699 -3.51638,-1.69963 -1.94005,-0.97122 -3.6376,-2.42803 -1.8188,-1.33542 -2.78884,-3.15646 -1.09128,-1.69963 -0.60626,-3.76347 0.48502,-1.82104 2.30383,-4.49187 1.69755,-2.67085 4.12261,-5.70591 2.54633,-3.03505 5.57768,-6.1915 3.15261,-3.03505 6.3052,-5.82729 3.27385,-2.79225 6.3052,-4.85609 3.15258,-2.06384 5.82015,-3.03506 0.36376,-0.12142 0.72754,-1.82103 0.36375,-1.69964 0.12115,-4.49187 -0.12115,-1.45684 -0.72752,-3.15646 -0.48502,-1.69963 -1.45505,-3.03505 -0.84876,-1.33543 -2.18254,-2.18525 -1.3338,-0.97122 -2.91009,-0.97122 -2.78884,0 -5.82018,2.91365 -3.03134,2.54946 -5.57767,1.82104 -2.4251,-0.72842 -3.7589,-3.03506 -1.21252,-2.42803 -0.84877,-5.46309 0.48502,-3.03505 3.39511,-5.09889 0.97004,-0.60702 4.00138,-3.03505 3.03135,-2.54945 6.66897,-5.7059 3.63759,-3.15646 7.03269,-6.31292 3.39512,-3.27785 5.09267,-5.3417 1.57629,-1.94242 2.0613,-3.03504 0.48502,-1.09261 0.36376,-1.69963 -0.12116,-0.60702 -0.72752,-0.72842 -0.48502,-0.2428 -0.84877,-0.2428 -1.45505,-0.12141 -3.3951,-0.2428 -1.81881,-0.12142 -3.51636,0 -1.69754,0.12128 -3.15259,0.4856 -1.33379,0.2428 -1.81881,0.72842 -0.97002,0.7284 -3.03134,3.88487 -1.94005,3.03505 -4.24386,6.67711 -2.30383,3.64207 -4.48642,7.04132 -2.06132,3.39927 -3.03135,4.85609 -2.18257,3.03505 -4.36511,3.88487 -2.30382,0.72842 -3.88012,0 -1.57631,-0.72841 -1.94007,-2.54945 -0.48501,-1.82102 0.84878,-4.00627 1.45505,-2.30664 3.1526,-5.34169 1.69754,-3.15646 3.51636,-6.55571 1.81878,-3.52067 3.63759,-7.16274 1.94008,-3.64206 3.75889,-7.16273 1.3338,-2.42803 2.78885,-3.88487 1.45503,-1.57822 3.8801,-2.42803 2.9101,-0.72842 6.42644,-0.97122 3.63761,-0.24281 7.15397,-0.12141 3.51636,0 6.66895,0.3642 3.15259,0.2428 5.2139,0.36422 2.30381,0.24279 4.48638,1.94243 2.30383,1.69962 3.88013,3.88485 1.69755,2.18524 2.42507,4.6133 0.72752,2.30664 -0.12116,3.88486 -0.12115,0.24281 -1.45503,1.57823 -1.33379,1.33543 -3.51636,3.39927 -2.06131,2.06383 -4.7289,4.61327 -2.66758,2.42805 -5.33516,4.97749 -2.54633,2.42805 -4.9714,4.61329 -2.42506,2.18523 -4.00137,3.64205 h 1.45505 q 4.60763,0 7.88149,0.72842 3.39511,0.607 6.54769,3.27785 2.66758,-3.03505 5.57768,-7.52693 2.91008,-4.61328 5.45641,-8.74095 2.30381,-4.00628 4.60764,-5.22029 2.42506,-1.21402 4.12263,-0.60702 1.81879,0.48561 2.42507,2.54946 0.72751,1.94243 -0.36376,4.49186 -6.79022,11.0476 -11.15534,18.21033 -4.24387,7.04132 -6.30518,9.95498 z"
|
||||||
|
fill={pathFill}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default LogoIcon;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// OUTLINED
|
||||||
|
export { default as IconArrowLeft } from './outlined/arrow-left.svg?react';
|
||||||
|
export { default as IconHomeOutline } from './outlined/home.svg?react';
|
||||||
|
export { default as IconUserOutline } from './outlined/user.svg?react';
|
||||||
|
export { default as IconCalendarStats } from './outlined/calendar-stats.svg?react';
|
||||||
|
export { default as IconDeviceDesktopAnalytics } from './outlined/device-desktop-analytics.svg?react';
|
||||||
|
export { default as IconFingerprint } from './outlined/fingerprint.svg?react';
|
||||||
|
export { default as IconGauge } from './outlined/gauge.svg?react';
|
||||||
|
export { default as IconHome2 } from './outlined/home-2.svg?react';
|
||||||
|
export { default as IconSettings } from './outlined/settings.svg?react';
|
||||||
|
export { default as IconArrowBarLeft } from './outlined/arrow-bar-left.svg?react';
|
||||||
|
export { default as IconArrowBarRight } from './outlined/arrow-bar-right.svg?react';
|
||||||
|
export { default as IconCheck } from './outlined/check.svg?react';
|
||||||
|
|
||||||
|
|
||||||
|
// FILLED
|
||||||
|
export { default as IconHomeFilled } from './filled/home.svg?react';
|
||||||
|
export { default as IconUserFilled } from './filled/user.svg?react';
|
||||||
+30
-41
@@ -10,25 +10,28 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-family:
|
||||||
.collapsed {
|
Greycliff CF,
|
||||||
width: 70px; /* Ancho reducido cuando colapsa */
|
var(--mantine-font-family);
|
||||||
|
margin-bottom: var(--mantine-spacing-sm);
|
||||||
|
background-color: var(--mantine-color-body);
|
||||||
|
padding: var(--mantine-spacing-xs);
|
||||||
|
padding-top: 15px;
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapseButton {
|
/* Esta es la barra izquierda pequeña donde los iconos */
|
||||||
margin-top: auto; /* Hace que el botón se empuje hacia abajo */
|
|
||||||
margin-bottom: 16px; /* ← Agrega separación del borde inferior */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.aside {
|
.aside {
|
||||||
flex: 0 0 60px;
|
flex: 0 0 52px;
|
||||||
background-color: var(--mantine-color-body);
|
background-color: var(--mantine-color-body);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -41,9 +44,16 @@
|
|||||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
|
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topSection {
|
||||||
|
padding-top: 12px; /* o la cantidad que desees */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Estos son los iconos */
|
||||||
.mainLink {
|
.mainLink {
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 4px;
|
||||||
border-radius: var(--mantine-radius-md);
|
border-radius: var(--mantine-radius-md);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -57,33 +67,13 @@
|
|||||||
&[data-active] {
|
&[data-active] {
|
||||||
&,
|
&,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--mantine-color-blue-light);
|
background-color: var(--mantine-color-brand-7);
|
||||||
color: var(--mantine-color-blue-light-color);
|
color: var(--mantine-color-brand-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
|
||||||
font-family:
|
|
||||||
Greycliff CF,
|
|
||||||
var(--mantine-font-family);
|
|
||||||
margin-bottom: var(--mantine-spacing-xl);
|
|
||||||
background-color: var(--mantine-color-body);
|
|
||||||
padding: var(--mantine-spacing-md);
|
|
||||||
padding-top: 18px;
|
|
||||||
height: 60px;
|
|
||||||
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
height: 60px;
|
|
||||||
padding-top: var(--mantine-spacing-md);
|
|
||||||
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
|
|
||||||
margin-bottom: var(--mantine-spacing-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -94,9 +84,9 @@
|
|||||||
padding: 0 var(--mantine-spacing-md);
|
padding: 0 var(--mantine-spacing-md);
|
||||||
font-size: var(--mantine-font-size-sm);
|
font-size: var(--mantine-font-size-sm);
|
||||||
margin-right: var(--mantine-spacing-md);
|
margin-right: var(--mantine-spacing-md);
|
||||||
font-weight: 500;
|
font-weight: 420;
|
||||||
height: 44px;
|
height: 30px;
|
||||||
line-height: 44px;
|
line-height: 30px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
|
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
|
||||||
@@ -106,9 +96,8 @@
|
|||||||
&[data-active] {
|
&[data-active] {
|
||||||
&,
|
&,
|
||||||
&:hover {
|
&:hover {
|
||||||
border-left-color: var(--mantine-color-blue-filled);
|
background-color: var(--mantine-color-brand-7);
|
||||||
background-color: var(--mantine-color-blue-filled);
|
color: var(--mantine-color-brand-2);
|
||||||
color: var(--mantine-color-white);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
import {
|
||||||
|
AppShell,
|
||||||
|
Burger,
|
||||||
|
Group,
|
||||||
|
Tooltip,
|
||||||
|
UnstyledButton,
|
||||||
|
Title,
|
||||||
|
useMantineTheme,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { useDisclosure, useMediaQuery } from '@mantine/hooks';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { default as LogoIcon } from '../../assets/icons/favicon';
|
||||||
|
import { mainLinksdata } from '../../data/navigationsLinks_1';
|
||||||
|
import { submenuLinks } from '../../data/submenuLinks_1';
|
||||||
|
|
||||||
|
import classes from './Appshell.module.css';
|
||||||
|
|
||||||
|
type AppShellWithMenuProps = {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Persistencia en localStorage
|
||||||
|
const STORAGE_KEY = 'lastSubmenuRoutes';
|
||||||
|
|
||||||
|
function getLastSubmenuRoute(section: string): string | null {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(STORAGE_KEY);
|
||||||
|
const parsed = raw ? JSON.parse(raw) : {};
|
||||||
|
return parsed[section] ?? null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLastSubmenuRoute(section: string, route: string) {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(STORAGE_KEY);
|
||||||
|
const parsed = raw ? JSON.parse(raw) : {};
|
||||||
|
parsed[section] = route;
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(parsed));
|
||||||
|
} catch {
|
||||||
|
// fallback silencioso
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AppShellWithMenu({ children }: AppShellWithMenuProps) {
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const isMobile = useMediaQuery('(max-width: 768px)');
|
||||||
|
const [mobileOpened, { toggle: toggleMobile, close: closeMobile }] = useDisclosure(false);
|
||||||
|
const [desktopOpened, { toggle: toggleDesktop, open: openDesktop }] = useDisclosure(true);
|
||||||
|
|
||||||
|
const isCollapsed = useMemo(
|
||||||
|
() => (isMobile ? !mobileOpened : !desktopOpened),
|
||||||
|
[isMobile, mobileOpened, desktopOpened]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Estado para el main link activo
|
||||||
|
const [activeMain, setActiveMain] = useState<string>('Home');
|
||||||
|
|
||||||
|
// Ref para saber si el usuario ha hecho clic manualmente en el main link
|
||||||
|
const userClickedMainRef = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentPath = location.pathname.toLowerCase().replace(/\/$/, '');
|
||||||
|
|
||||||
|
let matchedMain: string | null = null;
|
||||||
|
let maxMatchLength = 0;
|
||||||
|
|
||||||
|
Object.entries(submenuLinks).forEach(([main, items]) => {
|
||||||
|
items.forEach((item) => {
|
||||||
|
const itemPath = item.to.toLowerCase().replace(/\/$/, '');
|
||||||
|
if (
|
||||||
|
currentPath === itemPath ||
|
||||||
|
currentPath.startsWith(itemPath + '/')
|
||||||
|
) {
|
||||||
|
if (itemPath.length > maxMatchLength) {
|
||||||
|
matchedMain = main;
|
||||||
|
maxMatchLength = itemPath.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matchedMain) {
|
||||||
|
setActiveMain(matchedMain);
|
||||||
|
}
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
const activeLink =
|
||||||
|
submenuLinks[activeMain as keyof typeof submenuLinks]?.find(
|
||||||
|
(item) => item.to === location.pathname
|
||||||
|
)?.label ?? '';
|
||||||
|
|
||||||
|
const mainLinks = mainLinksdata.map((link) => (
|
||||||
|
<Tooltip
|
||||||
|
label={link.label}
|
||||||
|
position="right"
|
||||||
|
withArrow
|
||||||
|
transitionProps={{ duration: 0 }}
|
||||||
|
key={link.label}
|
||||||
|
>
|
||||||
|
<UnstyledButton
|
||||||
|
onClick={() => {
|
||||||
|
userClickedMainRef.current = true;
|
||||||
|
setActiveMain(link.label);
|
||||||
|
|
||||||
|
const remembered = getLastSubmenuRoute(link.label);
|
||||||
|
const fallback = submenuLinks[link.label as keyof typeof submenuLinks]?.[0]?.to;
|
||||||
|
|
||||||
|
if (isCollapsed && (remembered || fallback)) {
|
||||||
|
navigate(remembered ?? fallback);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={classes.mainLink}
|
||||||
|
data-active={link.label === activeMain || undefined}
|
||||||
|
>
|
||||||
|
<link.icon />
|
||||||
|
</UnstyledButton>
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
const links = (submenuLinks[activeMain as keyof typeof submenuLinks] || []).map((item) => (
|
||||||
|
<Link
|
||||||
|
className={classes.link}
|
||||||
|
data-active={activeLink === item.label || undefined}
|
||||||
|
to={item.to}
|
||||||
|
key={item.label}
|
||||||
|
style={{ display: isCollapsed ? 'none' : 'block' }}
|
||||||
|
onClick={() => {
|
||||||
|
setLastSubmenuRoute(activeMain, item.to);
|
||||||
|
if (isMobile) closeMobile();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMobile) openDesktop();
|
||||||
|
}, [isMobile, openDesktop]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShell
|
||||||
|
header={{ height: 60 }}
|
||||||
|
navbar={{
|
||||||
|
width: isCollapsed ? 60 : 300,
|
||||||
|
breakpoint: 'sm',
|
||||||
|
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
|
||||||
|
}}
|
||||||
|
padding="md"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<AppShell.Header>
|
||||||
|
<Group h="100%" px="sm">
|
||||||
|
<Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" size="sm" />
|
||||||
|
<Burger opened={desktopOpened} onClick={toggleDesktop} visibleFrom="sm" size="sm" />
|
||||||
|
<LogoIcon
|
||||||
|
style={{ width: 30, height: 30 }}
|
||||||
|
circleFill={theme.colors.brand[9]}
|
||||||
|
pathFill={theme.colors.secondary[2]}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</AppShell.Header>
|
||||||
|
|
||||||
|
{/* Navbar */}
|
||||||
|
<AppShell.Navbar>
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<div className={classes.aside}>
|
||||||
|
<div className={classes.topSection}>{mainLinks}</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes.main}>
|
||||||
|
{!isCollapsed && (
|
||||||
|
<Title order={4} className={classes.title}>
|
||||||
|
{activeMain}
|
||||||
|
</Title>
|
||||||
|
)}
|
||||||
|
{links}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AppShell.Navbar>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<AppShell.Main>{children}</AppShell.Main>
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
import {
|
|
||||||
IconCalendarStats,
|
|
||||||
IconDeviceDesktopAnalytics,
|
|
||||||
IconFingerprint,
|
|
||||||
IconGauge,
|
|
||||||
IconHome2,
|
|
||||||
IconSettings,
|
|
||||||
IconUser,
|
|
||||||
IconArrowBarLeft,
|
|
||||||
IconArrowBarRight,
|
|
||||||
} from '@tabler/icons-react';
|
|
||||||
import {
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
UnstyledButton,
|
|
||||||
ActionIcon,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import classes from './DoubleNavbar.module.css';
|
|
||||||
|
|
||||||
const mainLinksdata = [
|
|
||||||
{ icon: IconHome2, label: 'Home' },
|
|
||||||
{ icon: IconGauge, label: 'Dashboard' },
|
|
||||||
{ icon: IconDeviceDesktopAnalytics, label: 'Analytics' },
|
|
||||||
{ icon: IconCalendarStats, label: 'Releases' },
|
|
||||||
{ icon: IconUser, label: 'Account' },
|
|
||||||
{ icon: IconFingerprint, label: 'Security' },
|
|
||||||
{ icon: IconSettings, label: 'Settings' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const submenuLinks: Record<string, { label: string; to: string }[]> = {
|
|
||||||
Home: [
|
|
||||||
{ label: 'Inicio', to: '/' },
|
|
||||||
{ label: 'Consulta Api', to: '/Consulta_API' },
|
|
||||||
],
|
|
||||||
Dashboard: [
|
|
||||||
{ label: 'Resumen', to: '/dashboard/resumen' },
|
|
||||||
{ label: 'Estadísticas', to: '/dashboard/estadisticas' },
|
|
||||||
{ label: 'Usuarios', to: '/dashboard/usuarios' },
|
|
||||||
],
|
|
||||||
Analytics: [
|
|
||||||
{ label: 'Conversiones', to: '/analytics/conversiones' },
|
|
||||||
{ label: 'Tráfico', to: '/analytics/trafico' },
|
|
||||||
{ label: 'Tendencias', to: '/analytics/tendencias' },
|
|
||||||
],
|
|
||||||
Releases: [
|
|
||||||
{ label: 'Notas de versión', to: '/releases/notas-de-version' },
|
|
||||||
{ label: 'Historial', to: '/releases/historial' },
|
|
||||||
],
|
|
||||||
Account: [
|
|
||||||
{ label: 'Perfil', to: '/account/perfil' },
|
|
||||||
{ label: 'Suscripciones', to: '/account/suscripciones' },
|
|
||||||
],
|
|
||||||
Security: [
|
|
||||||
{ label: 'Contraseña', to: '/security/contraseña' },
|
|
||||||
{ label: '2FA', to: '/security/2fa' },
|
|
||||||
],
|
|
||||||
Settings: [
|
|
||||||
{ label: 'Preferencias', to: '/settings/preferencias' },
|
|
||||||
{ label: 'Notificaciones', to: '/settings/notificaciones' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export function DoubleNavbar() {
|
|
||||||
const location = useLocation();
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
const [manualActiveTab, setManualActiveTab] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// Detectar cuál pestaña es activa por la ruta actual
|
|
||||||
const matchedMain = Object.entries(submenuLinks).find(([mainKey, items]) =>
|
|
||||||
items.some((item) => location.pathname.startsWith(item.to))
|
|
||||||
);
|
|
||||||
|
|
||||||
const routeBasedActive = matchedMain?.[0] ?? 'Home';
|
|
||||||
const active = manualActiveTab ?? routeBasedActive;
|
|
||||||
|
|
||||||
const activeLink =
|
|
||||||
submenuLinks[active]?.find((item) => location.pathname === item.to)?.label ?? '';
|
|
||||||
|
|
||||||
const mainLinks = mainLinksdata.map((link) => (
|
|
||||||
<Tooltip
|
|
||||||
label={link.label}
|
|
||||||
position="right"
|
|
||||||
withArrow
|
|
||||||
transitionProps={{ duration: 0 }}
|
|
||||||
key={link.label}
|
|
||||||
>
|
|
||||||
<UnstyledButton
|
|
||||||
onClick={() => setManualActiveTab(link.label)}
|
|
||||||
className={classes.mainLink}
|
|
||||||
data-active={link.label === active || undefined}
|
|
||||||
>
|
|
||||||
<link.icon size={22} stroke={1.5} />
|
|
||||||
</UnstyledButton>
|
|
||||||
</Tooltip>
|
|
||||||
));
|
|
||||||
|
|
||||||
const links = (submenuLinks[active] || []).map((item) => (
|
|
||||||
<Link
|
|
||||||
className={classes.link}
|
|
||||||
data-active={activeLink === item.label || undefined}
|
|
||||||
to={item.to}
|
|
||||||
key={item.label}
|
|
||||||
style={{ display: collapsed ? 'none' : 'block' }}
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Link>
|
|
||||||
));
|
|
||||||
|
|
||||||
// Resetea pestaña seleccionada si la ruta cambia (opcional)
|
|
||||||
useEffect(() => {
|
|
||||||
setManualActiveTab(null);
|
|
||||||
}, [location.pathname]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className={`${classes.navbar} ${collapsed ? classes.collapsed : ''}`}>
|
|
||||||
<div className={classes.wrapper}>
|
|
||||||
<div className={classes.aside}>
|
|
||||||
{/* Sección superior: logo + mainLinks */}
|
|
||||||
<div className={classes.topSection}>
|
|
||||||
<div className={classes.logo}>
|
|
||||||
<img
|
|
||||||
src="/src/favicon.svg"
|
|
||||||
alt="Logo"
|
|
||||||
style={{ width: 30, height: 30 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{mainLinks}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Botón de colapsar separado abajo */}
|
|
||||||
<ActionIcon
|
|
||||||
variant="subtle"
|
|
||||||
onClick={() => setCollapsed((c) => !c)}
|
|
||||||
className={classes.collapseButton}
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
{collapsed ? <IconArrowBarRight size={20} /> : <IconArrowBarLeft size={20} />}
|
|
||||||
</ActionIcon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes.main}>
|
|
||||||
{!collapsed && (
|
|
||||||
<Title order={4} className={classes.title}>
|
|
||||||
{active}
|
|
||||||
</Title>
|
|
||||||
)}
|
|
||||||
{links}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { Card, Text, Switch, Group, useMantineTheme, useComputedColorScheme } from '@mantine/core';
|
||||||
|
import { Rnd } from 'react-rnd';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const GRID_SIZE = 30;
|
||||||
|
|
||||||
|
function hexToRgba(hex: string, alpha: number): string {
|
||||||
|
const sanitized = hex.replace('#', '');
|
||||||
|
const bigint = parseInt(sanitized, 16);
|
||||||
|
|
||||||
|
const r = (bigint >> 16) & 255;
|
||||||
|
const g = (bigint >> 8) & 255;
|
||||||
|
const b = bigint & 255;
|
||||||
|
|
||||||
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CardData {
|
||||||
|
id: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialCards: CardData[] = [
|
||||||
|
{ id: '1', x: 0, y: 0, width: GRID_SIZE * 2, height: GRID_SIZE * 2 },
|
||||||
|
{ id: '2', x: GRID_SIZE * 2, y: 0, width: GRID_SIZE * 3, height: GRID_SIZE * 2 },
|
||||||
|
{ id: '3', x: GRID_SIZE * 3, y: 0, width: GRID_SIZE * 3, height: GRID_SIZE * 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const GridDashboard = () => {
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
const colorScheme = useComputedColorScheme(); // ✅ directamente 'light' o 'dark'
|
||||||
|
const isDark = colorScheme === 'dark';
|
||||||
|
|
||||||
|
// Color de la rejilla adaptado al modo del tema
|
||||||
|
const gridBaseColor = isDark ? theme.colors.dark[4] : theme.colors.gray[3];
|
||||||
|
const gridColor = hexToRgba(gridBaseColor, 0.25); // Ajusta la opacidad aquí
|
||||||
|
|
||||||
|
const [cards, setCards] = useState<CardData[]>(initialCards);
|
||||||
|
const [showGrid, setShowGrid] = useState(true);
|
||||||
|
|
||||||
|
const updateCard = (id: string, updates: Partial<CardData>) => {
|
||||||
|
setCards((prev) =>
|
||||||
|
prev.map((card) => (card.id === id ? { ...card, ...updates } : card))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Group mb="xs">
|
||||||
|
<Switch
|
||||||
|
checked={showGrid}
|
||||||
|
onChange={(event) => setShowGrid(event.currentTarget.checked)}
|
||||||
|
label="Mostrar cuadrícula"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '700px',
|
||||||
|
backgroundSize: `${GRID_SIZE}px ${GRID_SIZE}px`,
|
||||||
|
backgroundImage: showGrid
|
||||||
|
? `linear-gradient(to right, ${gridColor} 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)`
|
||||||
|
: 'none',
|
||||||
|
position: 'relative',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cards.map((card) => (
|
||||||
|
<Rnd
|
||||||
|
key={card.id}
|
||||||
|
size={{
|
||||||
|
width: Math.round(card.width / GRID_SIZE) * GRID_SIZE,
|
||||||
|
height: Math.round(card.height / GRID_SIZE) * GRID_SIZE,
|
||||||
|
}}
|
||||||
|
position={{ x: card.x, y: card.y }}
|
||||||
|
minWidth={GRID_SIZE * 8}
|
||||||
|
minHeight={GRID_SIZE * 8}
|
||||||
|
bounds="parent"
|
||||||
|
grid={[GRID_SIZE, GRID_SIZE]}
|
||||||
|
onDragStop={(_, d) =>
|
||||||
|
updateCard(card.id, {
|
||||||
|
x: Math.round(d.x / GRID_SIZE) * GRID_SIZE,
|
||||||
|
y: Math.round(d.y / GRID_SIZE) * GRID_SIZE,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onResizeStop={(_, __, ref, ___, pos) =>
|
||||||
|
updateCard(card.id, {
|
||||||
|
width: Math.round(ref.offsetWidth / GRID_SIZE) * GRID_SIZE,
|
||||||
|
height: Math.round(ref.offsetHeight / GRID_SIZE) * GRID_SIZE,
|
||||||
|
x: Math.round(pos.x / GRID_SIZE) * GRID_SIZE,
|
||||||
|
y: Math.round(pos.y / GRID_SIZE) * GRID_SIZE,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
shadow="sm"
|
||||||
|
padding="md"
|
||||||
|
radius="md"
|
||||||
|
withBorder
|
||||||
|
style={{ height: '100%', userSelect: 'none' }}
|
||||||
|
>
|
||||||
|
<Text fw={500}>Card {card.id}</Text>
|
||||||
|
<Text size="sm">Mueve o redimensiona</Text>
|
||||||
|
</Card>
|
||||||
|
</Rnd>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -58,7 +58,7 @@ extend({ HoloShaderMaterial });
|
|||||||
|
|
||||||
// 🎥 Plano con el shader
|
// 🎥 Plano con el shader
|
||||||
function HoloPlane({ color }: { color: [number, number, number] }) {
|
function HoloPlane({ color }: { color: [number, number, number] }) {
|
||||||
const mat = useRef<any>();
|
const mat = useRef<any>(null);
|
||||||
const { size } = useThree();
|
const { size } = useThree();
|
||||||
|
|
||||||
useFrame(({ clock }) => {
|
useFrame(({ clock }) => {
|
||||||
@@ -130,6 +130,8 @@ export function MantineCardWithShader() {
|
|||||||
WebkitTextFillColor: 'transparent',
|
WebkitTextFillColor: 'transparent',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
|
userSelect: 'none', // <-- evita selección
|
||||||
|
textDecoration: 'none', // <-- evita subrayado
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
404
|
404
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
TextInput,
|
||||||
|
Textarea,
|
||||||
|
Button,
|
||||||
|
Box,
|
||||||
|
Center,
|
||||||
|
Stack,
|
||||||
|
Badge,
|
||||||
|
Group,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { MetodoSelect } from './MetodoSelect';
|
||||||
|
import { useMantineTheme } from '@mantine/core';
|
||||||
|
|
||||||
|
export function LlamadorAPI() {
|
||||||
|
const [direccion, setDireccion] = useState('http://localhost:8000/api/v1/ping/');
|
||||||
|
const [metodo, setMetodo] = useState('GET');
|
||||||
|
const [contenido, setContenido] = useState('');
|
||||||
|
const [respuesta, setRespuesta] = useState('');
|
||||||
|
const [codigoRespuesta, setCodigoRespuesta] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const colorCodigo = (status: number): string => {
|
||||||
|
if (status >= 200 && status < 300) return 'green';
|
||||||
|
if (status >= 300 && status < 400) return 'yellow';
|
||||||
|
if (status >= 400 && status < 500) return 'orange';
|
||||||
|
return 'red';
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
|
||||||
|
|
||||||
|
const llamarAPI = async () => {
|
||||||
|
try {
|
||||||
|
const options: RequestInit = {
|
||||||
|
method: metodo,
|
||||||
|
mode: 'cors',
|
||||||
|
headers: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (metodo !== 'GET') {
|
||||||
|
options.headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
JSON.parse(contenido);
|
||||||
|
options.body = contenido;
|
||||||
|
} catch (err) {
|
||||||
|
setRespuesta('Error: El contenido no es un JSON válido');
|
||||||
|
setCodigoRespuesta(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(direccion, options);
|
||||||
|
setCodigoRespuesta(res.status);
|
||||||
|
|
||||||
|
const contentType = res.headers.get('content-type');
|
||||||
|
|
||||||
|
if (contentType?.includes('application/json')) {
|
||||||
|
const data = await res.json();
|
||||||
|
const formatted = JSON.stringify(data, null, 2);
|
||||||
|
setRespuesta(formatted);
|
||||||
|
} else {
|
||||||
|
const text = await res.text();
|
||||||
|
setRespuesta(text);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error en la API:', error);
|
||||||
|
setRespuesta(`Error: ${error.message || error}`);
|
||||||
|
setCodigoRespuesta(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e: KeyboardEvent) => {
|
||||||
|
if (e.ctrlKey && e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
llamarAPI();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handler);
|
||||||
|
return () => window.removeEventListener('keydown', handler);
|
||||||
|
}, [metodo, direccion, contenido]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box style={{ flex: 1, padding: 40 }}>
|
||||||
|
<Center style={{ height: '100%' }}>
|
||||||
|
<Stack style={{ width: 600 }}>
|
||||||
|
<TextInput
|
||||||
|
label="Dirección"
|
||||||
|
placeholder="http://localhost:8000/api/..."
|
||||||
|
value={direccion}
|
||||||
|
onChange={(e) => setDireccion(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MetodoSelect metodo={metodo} setMetodo={setMetodo} />
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="Contenido (JSON)"
|
||||||
|
placeholder='{"contenido": "Hola"}'
|
||||||
|
value={contenido}
|
||||||
|
onChange={(e) => setContenido(e.currentTarget.value)}
|
||||||
|
autosize
|
||||||
|
minRows={3}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button onClick={llamarAPI}
|
||||||
|
variant="gradient"
|
||||||
|
gradient={{
|
||||||
|
from: theme.colors.brand[7],
|
||||||
|
to: theme.colors.brand[4],
|
||||||
|
}}>
|
||||||
|
Enviar solicitud
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{codigoRespuesta !== null && (
|
||||||
|
<Group>
|
||||||
|
<Badge color={colorCodigo(codigoRespuesta)} size="lg">
|
||||||
|
Código: {codigoRespuesta}
|
||||||
|
</Badge>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
label="Respuesta de la API"
|
||||||
|
value={respuesta}
|
||||||
|
readOnly
|
||||||
|
autosize
|
||||||
|
minRows={6}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Select, Group } from '@mantine/core';
|
import { Select, Group } from '@mantine/core';
|
||||||
import { IconCheck } from '@tabler/icons-react';
|
import { IconCheck } from '../assets/icons';
|
||||||
|
|
||||||
interface MetodoSelectProps {
|
interface MetodoSelectProps {
|
||||||
metodo: string;
|
metodo: string;
|
||||||
@@ -37,7 +37,7 @@ export function MetodoSelect({ metodo, setMetodo }: MetodoSelectProps) {
|
|||||||
renderOption={({ option, checked }) => (
|
renderOption={({ option, checked }) => (
|
||||||
<Group style={{ color: colorMap[option.value], fontWeight: 600 }}>
|
<Group style={{ color: colorMap[option.value], fontWeight: 600 }}>
|
||||||
{option.label}
|
{option.label}
|
||||||
{checked && <IconCheck size={14} />}
|
{checked && <IconCheck/>}
|
||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
styles={{
|
styles={{
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import { Anchor, Text, Title } from '@mantine/core';
|
import { Anchor, Text, Title } from '@mantine/core';
|
||||||
import classes from './Welcome.module.css';
|
import classes from './Welcome.module.css';
|
||||||
|
import { useMantineTheme } from '@mantine/core';
|
||||||
|
|
||||||
export function Welcome() {
|
export function Welcome() {
|
||||||
|
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title className={classes.title} ta="center" mt={100}>
|
<Title className={classes.title} ta="center" mt={100}>
|
||||||
Hola! {' '}
|
Hola! {' '}
|
||||||
<Text inherit variant="gradient" component="span" gradient={{ from: 'blue', to: 'green' }} style={{ letterSpacing: '1px' }}>
|
<Text inherit variant="gradient" component="span" gradient={{ from: theme.colors.brand[7], to: theme.colors.secondary[4], }} style={{ letterSpacing: '1px' }}>
|
||||||
Egutierrez
|
Holooooo
|
||||||
</Text>
|
</Text>
|
||||||
</Title>
|
</Title>
|
||||||
<Text c="dimmed" ta="left" size="lg" maw={580} mx="auto" mt="xl">
|
<Text c="dimmed" ta="left" size="lg" maw={580} mx="auto" mt="xl">
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
// src/components/MiBoton.tsx
|
|
||||||
|
|
||||||
import { Button } from '@mantine/core';
|
|
||||||
import { MouseEventHandler } from 'react';
|
|
||||||
|
|
||||||
type MiBotonProps = {
|
|
||||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
|
||||||
label?: string;
|
|
||||||
color?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function MiBoton({ onClick, label = 'Hola que tal!', color = 'teal' }: MiBotonProps) {
|
|
||||||
return <Button color={color} onClick={onClick}>{label}</Button>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MiBoton;
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// src/data/navigationLinks.ts
|
||||||
|
import {
|
||||||
|
IconCalendarStats,
|
||||||
|
IconDeviceDesktopAnalytics,
|
||||||
|
IconFingerprint,
|
||||||
|
IconGauge,
|
||||||
|
IconHome2,
|
||||||
|
IconSettings,
|
||||||
|
IconUserOutline as IconUser,
|
||||||
|
} from '../assets/icons'; // ajusta según tu estructura de proyecto
|
||||||
|
|
||||||
|
export const mainLinksdata = [
|
||||||
|
{ icon: IconHome2, label: 'Home' },
|
||||||
|
{ icon: IconGauge, label: 'Dashboard' },
|
||||||
|
{ icon: IconDeviceDesktopAnalytics, label: 'Analytics' },
|
||||||
|
{ icon: IconCalendarStats, label: 'Releases' },
|
||||||
|
{ icon: IconUser, label: 'Account' },
|
||||||
|
{ icon: IconFingerprint, label: 'Security' },
|
||||||
|
{ icon: IconSettings, label: 'Settings' },
|
||||||
|
];
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// src/data/submenuLinks.ts
|
||||||
|
|
||||||
|
export const submenuLinks = {
|
||||||
|
Home: [
|
||||||
|
{ label: 'Inicio', to: '/' },
|
||||||
|
{ label: 'Consulta Api', to: '/Consulta_API' },
|
||||||
|
{ label: 'Biblioteca', to: '/Biblioteca' },
|
||||||
|
|
||||||
|
],
|
||||||
|
Dashboard: [
|
||||||
|
{ label: 'Resumen', to: '/dashboard/resumen' },
|
||||||
|
{ label: 'Grid_Dashboard', to: '/Grid_Dashboard' },
|
||||||
|
{ label: 'Estadísticas', to: '/dashboard/estadisticas' },
|
||||||
|
{ label: 'Usuarios', to: '/dashboard/usuarios' },
|
||||||
|
],
|
||||||
|
Analytics: [
|
||||||
|
{ label: 'Conversiones', to: '/analytics/conversiones' },
|
||||||
|
{ label: 'Tráfico', to: '/analytics/trafico' },
|
||||||
|
{ label: 'Tendencias', to: '/analytics/tendencias' },
|
||||||
|
],
|
||||||
|
Releases: [
|
||||||
|
{ label: 'Notas de versión', to: '/releases/notas-de-version' },
|
||||||
|
{ label: 'Historial', to: '/releases/historial' },
|
||||||
|
],
|
||||||
|
Account: [
|
||||||
|
{ label: 'Perfil', to: '/account/perfil' },
|
||||||
|
{ label: 'Suscripciones', to: '/account/suscripciones' },
|
||||||
|
],
|
||||||
|
Security: [
|
||||||
|
{ label: 'Contraseña', to: '/security/contraseña' },
|
||||||
|
{ label: '2FA', to: '/security/2fa' },
|
||||||
|
],
|
||||||
|
Settings: [
|
||||||
|
{ label: 'Preferencias', to: '/settings/preferencias' },
|
||||||
|
{ label: 'Notificaciones', to: '/settings/notificaciones' },
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 163 163"><path fill="#339AF0" d="M162.162 81.5c0-45.011-36.301-81.5-81.08-81.5C36.301 0 0 36.489 0 81.5 0 126.51 36.301 163 81.081 163s81.081-36.49 81.081-81.5z"/><path fill="#fff" d="M65.983 43.049a6.234 6.234 0 00-.336 6.884 6.14 6.14 0 001.618 1.786c9.444 7.036 14.866 17.794 14.866 29.52 0 11.726-5.422 22.484-14.866 29.52a6.145 6.145 0 00-1.616 1.786 6.21 6.21 0 00-.694 4.693 6.21 6.21 0 001.028 2.186 6.151 6.151 0 006.457 2.319 6.154 6.154 0 002.177-1.035 50.083 50.083 0 007.947-7.39h17.493c3.406 0 6.174-2.772 6.174-6.194s-2.762-6.194-6.174-6.194h-9.655a49.165 49.165 0 004.071-19.69 49.167 49.167 0 00-4.07-19.692h9.66c3.406 0 6.173-2.771 6.173-6.194 0-3.422-2.762-6.193-6.173-6.193H82.574a50.112 50.112 0 00-7.952-7.397 6.15 6.15 0 00-4.578-1.153 6.189 6.189 0 00-4.055 2.438h-.006z"/><path fill="#fff" fill-rule="evenodd" d="M56.236 79.391a9.342 9.342 0 01.632-3.608 9.262 9.262 0 011.967-3.077 9.143 9.143 0 012.994-2.063 9.06 9.06 0 017.103 0 9.145 9.145 0 012.995 2.063 9.262 9.262 0 011.967 3.077 9.339 9.339 0 01-2.125 10.003 9.094 9.094 0 01-6.388 2.63 9.094 9.094 0 01-6.39-2.63 9.3 9.3 0 01-2.755-6.395z" clip-rule="evenodd"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
+36
-19
@@ -1,31 +1,44 @@
|
|||||||
import { Box, Title, Text, Button, Group, Stack, Image, Center } from '@mantine/core';
|
import { Box, Title, Text, Button, Group, Stack, Image, Center } from '@mantine/core';
|
||||||
import { IconArrowLeft } from '@tabler/icons-react';
|
import { useMantineTheme } from '@mantine/core';
|
||||||
|
import { IconArrowLeft } from '../assets/icons';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar'; // Ajusta ruta si es necesario
|
|
||||||
import { MantineCardWithShader } from '../components/HoloShader'; // Ajusta ruta si es necesario
|
import { MantineCardWithShader } from '../components/HoloShader'; // Ajusta ruta si es necesario
|
||||||
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
|
|
||||||
|
|
||||||
export function Error_404() {
|
export function Error_404() {
|
||||||
|
|
||||||
|
const theme = useMantineTheme();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar />
|
<Box
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
<Box style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '2rem' }}>
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
padding: '2rem',
|
||||||
|
paddingTop: '0.5rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '2rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Stack align="center" maw={500} mx="auto">
|
<Stack align="center" maw={500} mx="auto">
|
||||||
|
|
||||||
|
|
||||||
<MantineCardWithShader />
|
<MantineCardWithShader />
|
||||||
|
<Title order={1}>Página no encontrada</Title>
|
||||||
|
|
||||||
<Title order={1}>
|
|
||||||
Página no encontrada
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
<Text size="lg">
|
<Text size="lg">
|
||||||
Parece que la página que estás buscando no existe o fue removida. Pero no te preocupes, puedes volver al inicio fácilmente.
|
Parece que la página que estás buscando no existe o fue removida. Pero no te preocupes,
|
||||||
|
puedes volver al inicio fácilmente.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Group mt="md">
|
<Group mt="md">
|
||||||
@@ -34,8 +47,11 @@ export function Error_404() {
|
|||||||
to="/"
|
to="/"
|
||||||
size="md"
|
size="md"
|
||||||
variant="gradient"
|
variant="gradient"
|
||||||
gradient={{ from: 'blue', to: 'cyan' }}
|
gradient={{
|
||||||
leftSection={<IconArrowLeft size={18} />}
|
from: theme.colors.brand[7],
|
||||||
|
to: theme.colors.secondary[4],
|
||||||
|
}}
|
||||||
|
leftSection={<IconArrowLeft width={18} height={18} />}
|
||||||
>
|
>
|
||||||
Volver al inicio
|
Volver al inicio
|
||||||
</Button>
|
</Button>
|
||||||
@@ -43,5 +59,6 @@ export function Error_404() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
</AppShellWithMenu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,11 @@
|
|||||||
import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeToggle';
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
import { Welcome } from '../components/Welcome/Welcome';
|
|
||||||
import MiBoton from '../components/botoncito';
|
|
||||||
import { Center, Box } from '@mantine/core';
|
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function Prueba_1() {
|
export function Prueba_1() {
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar /> {/* Sidebar fijo a la izquierda */}
|
|
||||||
|
|
||||||
{/* Contenido principal */}
|
</AppShellWithMenu>
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
AppShell,
|
||||||
|
Stack,
|
||||||
|
Card,
|
||||||
|
Text,
|
||||||
|
Title,
|
||||||
|
ScrollArea,
|
||||||
|
Group,
|
||||||
|
Button,
|
||||||
|
TextInput,
|
||||||
|
Modal,
|
||||||
|
Box,
|
||||||
|
Loader,
|
||||||
|
Textarea
|
||||||
|
} 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 [notaEnEdicion, setNotaEnEdicion] = useState<Nota | null>(null);
|
||||||
|
const [modalEditarAbierto, setModalEditarAbierto] = useState(false);
|
||||||
|
const [modalNuevaBiblio, setModalNuevaBiblio] = useState(false);
|
||||||
|
const [nombreBiblio, setNombreBiblio] = useState('');
|
||||||
|
const [descripcionBiblio, setDescripcionBiblio] = useState('');
|
||||||
|
const [loadingNuevaBiblio, setLoadingNuevaBiblio] = 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 crearBiblioteca = async () => {
|
||||||
|
setLoadingNuevaBiblio(true); // 🔄 Activa el loader en el botón
|
||||||
|
try {
|
||||||
|
// Llamada a backend
|
||||||
|
await axios.post('/api/v1/text_manager/biblioteca', {
|
||||||
|
nombre_biblioteca: nombreBiblio,
|
||||||
|
descripcion: descripcionBiblio,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 🧼 Limpia formularios
|
||||||
|
setNombreBiblio('');
|
||||||
|
setDescripcionBiblio('');
|
||||||
|
|
||||||
|
// 🔒 Cierra el modal
|
||||||
|
setModalNuevaBiblio(false);
|
||||||
|
|
||||||
|
// 🔄 Refresca la lista de bibliotecas
|
||||||
|
await fetchBibliotecas();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error al crear biblioteca:', error);
|
||||||
|
} finally {
|
||||||
|
setLoadingNuevaBiblio(false); // ✅ Apaga el loader
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Eliminar nota
|
||||||
|
const eliminarNota = async (notaId: string) => {
|
||||||
|
if (!bibliotecaSeleccionada) return;
|
||||||
|
try {
|
||||||
|
await axios.delete(`/api/v1/text_manager/nota/${bibliotecaSeleccionada.id}/${notaId}`);
|
||||||
|
|
||||||
|
// Solo actualiza la biblioteca actual
|
||||||
|
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);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error al eliminar nota:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Editar nota
|
||||||
|
const abrirModalEditar = (nota: Nota) => {
|
||||||
|
setNotaEnEdicion(nota);
|
||||||
|
setModalEditarAbierto(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Guardar cambios de edición
|
||||||
|
const guardarEdicionNota = async () => {
|
||||||
|
if (!notaEnEdicion || !bibliotecaSeleccionada) return;
|
||||||
|
try {
|
||||||
|
await axios.put(`/api/v1/text_manager/nota/${bibliotecaSeleccionada.id}/${notaEnEdicion.id}`, {
|
||||||
|
titulo: notaEnEdicion.titulo,
|
||||||
|
texto: notaEnEdicion.texto,
|
||||||
|
tags: [],
|
||||||
|
conexiones: [],
|
||||||
|
resumen: ""
|
||||||
|
});
|
||||||
|
setModalEditarAbierto(false);
|
||||||
|
setNotaEnEdicion(null);
|
||||||
|
await fetchBibliotecas();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error al actualizar nota:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShellWithMenu>
|
||||||
|
<Box display="flex" h="100%">
|
||||||
|
<Box w={240} p="md">
|
||||||
|
<ScrollArea h="100%">
|
||||||
|
<Stack>
|
||||||
|
<Button color="teal" onClick={fetchBibliotecas}>🔄 Recuperar bibliotecas</Button>
|
||||||
|
<Button color="grape" variant="outline" onClick={() => setModalNuevaBiblio(true)}>➕ Nueva biblioteca</Button>
|
||||||
|
|
||||||
|
|
||||||
|
{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 onClick={() => setModalAbierto(true)}>Agregar nota</Button>
|
||||||
|
</Group>
|
||||||
|
<Group>
|
||||||
|
{loadingNotas ? (
|
||||||
|
<Loader />
|
||||||
|
) : (
|
||||||
|
bibliotecaSeleccionada.notas.map((nota) => (
|
||||||
|
|
||||||
|
// Cards de notas
|
||||||
|
|
||||||
|
<Card
|
||||||
|
key={nota.id}
|
||||||
|
shadow="sm"
|
||||||
|
padding="lg"
|
||||||
|
radius="md"
|
||||||
|
withBorder
|
||||||
|
style={{
|
||||||
|
width: 300,
|
||||||
|
height: 250, // Altura fija para asegurar la separación
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Title order={4} style={{ marginBottom: 10 }}>{nota.titulo}</Title>
|
||||||
|
<Text>{nota.texto}</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Box mt="md" style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
onClick={() => abrirModalEditar(nota)}
|
||||||
|
>
|
||||||
|
Editar
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
// Fin de notas en cards
|
||||||
|
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Stack>
|
||||||
|
<Text>Selecciona una biblioteca</Text>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Modal para agregar */}
|
||||||
|
<Modal opened={modalAbierto} onClose={() => setModalAbierto(false)} title="Agregar nueva nota">
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label="Título"
|
||||||
|
value={tituloNota}
|
||||||
|
onChange={(event) => setTituloNota(event.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<Textarea
|
||||||
|
label="Contenido"
|
||||||
|
minRows={6}
|
||||||
|
autosize
|
||||||
|
value={contenidoNota}
|
||||||
|
onChange={(event) => setContenidoNota(event.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<Button onClick={agregarNota}>Guardar</Button>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* Modal para editar */}
|
||||||
|
<Modal opened={modalEditarAbierto} onClose={() => setModalEditarAbierto(false)} title="Editar nota">
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label="Título"
|
||||||
|
value={notaEnEdicion?.titulo || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setNotaEnEdicion((prev) => (prev ? { ...prev, titulo: e.currentTarget.value } : null))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Textarea
|
||||||
|
label="Contenido"
|
||||||
|
minRows={6}
|
||||||
|
autosize
|
||||||
|
value={notaEnEdicion?.texto || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setNotaEnEdicion((prev) => (prev ? { ...prev, texto: e.currentTarget.value } : null))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Group grow>
|
||||||
|
<Button color="blue" onClick={guardarEdicionNota}>
|
||||||
|
💾 Guardar cambios
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="red"
|
||||||
|
onClick={async () => {
|
||||||
|
if (!notaEnEdicion || !bibliotecaSeleccionada) return;
|
||||||
|
await eliminarNota(notaEnEdicion.id);
|
||||||
|
setModalEditarAbierto(false);
|
||||||
|
setNotaEnEdicion(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
🗑️ Eliminar nota
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* Modal para crear una biblioteca */}
|
||||||
|
<Modal
|
||||||
|
opened={modalNuevaBiblio}
|
||||||
|
onClose={() => setModalNuevaBiblio(false)}
|
||||||
|
title="Crear nueva biblioteca"
|
||||||
|
>
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label="Nombre"
|
||||||
|
value={nombreBiblio}
|
||||||
|
onChange={(e) => setNombreBiblio(e.currentTarget.value)}
|
||||||
|
disabled={loadingNuevaBiblio}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label="Descripción"
|
||||||
|
value={descripcionBiblio}
|
||||||
|
onChange={(e) => setDescripcionBiblio(e.currentTarget.value)}
|
||||||
|
disabled={loadingNuevaBiblio}
|
||||||
|
/>
|
||||||
|
<Button onClick={crearBiblioteca} loading={loadingNuevaBiblio}>
|
||||||
|
Crear
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
</AppShellWithMenu>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,139 +1,12 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import {
|
|
||||||
TextInput,
|
|
||||||
Textarea,
|
|
||||||
Button,
|
|
||||||
Box,
|
|
||||||
Center,
|
|
||||||
Stack,
|
|
||||||
Badge,
|
|
||||||
Group,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
|
||||||
import { MetodoSelect } from '../components/MetodoSelect'; // 👈 Importación del nuevo componente
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
|
|
||||||
|
import { LlamadorAPI } from '../components/LlamadorAPI';
|
||||||
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
|
|
||||||
|
|
||||||
export function Consulta_API() {
|
export function Consulta_API() {
|
||||||
const [direccion, setDireccion] = useState('http://localhost:8000/api/saludo');
|
|
||||||
const [metodo, setMetodo] = useState('GET');
|
|
||||||
const [contenido, setContenido] = useState('');
|
|
||||||
const [respuesta, setRespuesta] = useState('');
|
|
||||||
const [codigoRespuesta, setCodigoRespuesta] = useState<number | null>(null);
|
|
||||||
|
|
||||||
const colorCodigo = (status: number): string => {
|
|
||||||
if (status >= 200 && status < 300) return 'green';
|
|
||||||
if (status >= 300 && status < 400) return 'yellow';
|
|
||||||
if (status >= 400 && status < 500) return 'orange';
|
|
||||||
return 'red';
|
|
||||||
};
|
|
||||||
|
|
||||||
const llamarAPI = async () => {
|
|
||||||
try {
|
|
||||||
const options: RequestInit = {
|
|
||||||
method: metodo,
|
|
||||||
mode: 'cors',
|
|
||||||
headers: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (metodo !== 'GET') {
|
|
||||||
options.headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
JSON.parse(contenido);
|
|
||||||
options.body = contenido;
|
|
||||||
} catch (err) {
|
|
||||||
setRespuesta('Error: El contenido no es un JSON válido');
|
|
||||||
setCodigoRespuesta(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetch(direccion, options);
|
|
||||||
setCodigoRespuesta(res.status);
|
|
||||||
|
|
||||||
const contentType = res.headers.get('content-type');
|
|
||||||
|
|
||||||
if (contentType?.includes('application/json')) {
|
|
||||||
const data = await res.json();
|
|
||||||
const formatted = JSON.stringify(data, null, 2);
|
|
||||||
setRespuesta(formatted);
|
|
||||||
} else {
|
|
||||||
const text = await res.text();
|
|
||||||
setRespuesta(text);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('Error en la API:', error);
|
|
||||||
setRespuesta(`Error: ${error.message || error}`);
|
|
||||||
setCodigoRespuesta(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = (e: KeyboardEvent) => {
|
|
||||||
if (e.ctrlKey && e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
llamarAPI();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('keydown', handler);
|
|
||||||
return () => window.removeEventListener('keydown', handler);
|
|
||||||
}, [metodo, direccion, contenido]);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar />
|
<LlamadorAPI />
|
||||||
|
</AppShellWithMenu>
|
||||||
<Box style={{ flex: 1, padding: 40 }}>
|
|
||||||
<Center style={{ height: '100%' }}>
|
|
||||||
<Stack style={{ width: 600 }}>
|
|
||||||
<TextInput
|
|
||||||
label="Dirección"
|
|
||||||
placeholder="http://localhost:8000/api/..."
|
|
||||||
value={direccion}
|
|
||||||
onChange={(e) => setDireccion(e.currentTarget.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MetodoSelect metodo={metodo} setMetodo={setMetodo} />
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
label="Contenido (JSON)"
|
|
||||||
placeholder='{"contenido": "Hola"}'
|
|
||||||
value={contenido}
|
|
||||||
onChange={(e) => setContenido(e.currentTarget.value)}
|
|
||||||
autosize
|
|
||||||
minRows={3}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button onClick={llamarAPI} color="blue">
|
|
||||||
Enviar solicitud
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{codigoRespuesta !== null && (
|
|
||||||
<Group>
|
|
||||||
<Badge color={colorCodigo(codigoRespuesta)} size="lg">
|
|
||||||
Código: {codigoRespuesta}
|
|
||||||
</Badge>
|
|
||||||
</Group>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Textarea
|
|
||||||
label="Respuesta de la API"
|
|
||||||
value={respuesta}
|
|
||||||
readOnly
|
|
||||||
autosize
|
|
||||||
minRows={6}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Center>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Grid } from '@mantine/core';
|
||||||
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
|
import { GridDashboard } from '../components/Grid_dashboard';
|
||||||
|
|
||||||
|
export function Grid_Dashboard() {
|
||||||
|
return (
|
||||||
|
<AppShellWithMenu>
|
||||||
|
|
||||||
|
|
||||||
|
<GridDashboard></GridDashboard>
|
||||||
|
|
||||||
|
</AppShellWithMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,28 +1,22 @@
|
|||||||
import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeToggle';
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
import { Welcome } from '../components/Welcome/Welcome';
|
import { Welcome } from '@/components/Welcome/Welcome';
|
||||||
import MiBoton from '../components/botoncito';
|
import { ColorSchemeToggle } from '@/components/ColorSchemeToggle/ColorSchemeToggle';
|
||||||
import { Center, Box } from '@mantine/core';
|
|
||||||
import { DoubleNavbar } from '../components/DoubleNavbar';
|
|
||||||
import { MantineCardWithShader } from '../components/HoloShader';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function HomePage() {
|
export function HomePage() {
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', height: '100vh' }}>
|
<AppShellWithMenu>
|
||||||
<DoubleNavbar /> {/* Sidebar fijo a la izquierda */}
|
|
||||||
|
|
||||||
{/* Contenido principal */}
|
|
||||||
<Box style={{ flex: 1, padding: '24px' }}>
|
|
||||||
<Welcome />
|
<Welcome />
|
||||||
<ColorSchemeToggle />
|
|
||||||
|
<div style={{ padding: '20px' }}>
|
||||||
|
<h1>Welcome to the Home Page</h1>
|
||||||
|
<p>This is the home page content.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<Center mt="md">
|
<ColorSchemeToggle></ColorSchemeToggle>
|
||||||
<MiBoton />
|
|
||||||
</Center>
|
</AppShellWithMenu>
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||||
|
|
||||||
|
|
||||||
|
export function Plantilla() {
|
||||||
|
return (
|
||||||
|
<AppShellWithMenu>
|
||||||
|
|
||||||
|
</AppShellWithMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
+54
-1
@@ -1,5 +1,58 @@
|
|||||||
import { createTheme } from '@mantine/core';
|
import { createTheme } from '@mantine/core';
|
||||||
|
|
||||||
export const theme = createTheme({
|
export const theme = createTheme({
|
||||||
/** Put your mantine theme override here */
|
colors: {
|
||||||
|
// Definición de la paleta principal
|
||||||
|
brand: [
|
||||||
|
"#e7f2ff",
|
||||||
|
"#d0e1ff",
|
||||||
|
"#a1c0fa",
|
||||||
|
"#6e9df6",
|
||||||
|
"#447ff1",
|
||||||
|
"#296df0",
|
||||||
|
"#1863f0",
|
||||||
|
"#0753d6",
|
||||||
|
"#0049c1",
|
||||||
|
"#003faa"
|
||||||
|
],
|
||||||
|
// Puedes añadir hasta 3 colores adicionales si lo deseas
|
||||||
|
secondary: [
|
||||||
|
"#ecf4ff",
|
||||||
|
"#dce4f5",
|
||||||
|
"#b9c7e2",
|
||||||
|
"#94a8d0",
|
||||||
|
"#748dc0",
|
||||||
|
"#5f7cb7",
|
||||||
|
"#5474b4",
|
||||||
|
"#44639f",
|
||||||
|
"#3a5890",
|
||||||
|
"#2c4b80"
|
||||||
|
],
|
||||||
|
accent: [
|
||||||
|
'#fff3e0',
|
||||||
|
'#ffe0b2',
|
||||||
|
'#ffcc80',
|
||||||
|
'#ffb74d',
|
||||||
|
'#ffa726',
|
||||||
|
'#ff9800',
|
||||||
|
'#fb8c00',
|
||||||
|
'#f57c00',
|
||||||
|
'#ef6c00',
|
||||||
|
'#e65100',
|
||||||
|
],
|
||||||
|
neutral: [
|
||||||
|
'#fafafa',
|
||||||
|
'#f5f5f5',
|
||||||
|
'#eeeeee',
|
||||||
|
'#e0e0e0',
|
||||||
|
'#bdbdbd',
|
||||||
|
'#9e9e9e',
|
||||||
|
'#757575',
|
||||||
|
'#616161',
|
||||||
|
'#424242',
|
||||||
|
'#212121',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
primaryColor: 'brand', // Establece 'brand' como el color primario
|
||||||
|
primaryShade: { light: 6, dark: 8 }, // Define los tonos primarios para los esquemas de color claro y oscuro
|
||||||
});
|
});
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
declare module '*.svg' {
|
||||||
|
import * as React from 'react';
|
||||||
|
export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
|
||||||
|
const src: string;
|
||||||
|
export default src;
|
||||||
|
}
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite-plugin-svgr/client" />
|
||||||
@@ -21,5 +21,5 @@
|
|||||||
"@test-utils": ["./test-utils"]
|
"@test-utils": ["./test-utils"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src", "test-utils"]
|
"include": ["src", "src/types", "test-utils"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
import svgr from 'vite-plugin-svgr';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), tsconfigPaths()],
|
plugins: [react(), tsconfigPaths(), svgr()],
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:8000',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
test: {
|
test: {
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: 'jsdom',
|
environment: 'jsdom',
|
||||||
+289
-8
@@ -40,7 +40,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz"
|
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz"
|
||||||
integrity sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==
|
integrity sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==
|
||||||
|
|
||||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.18.9", "@babel/core@^7.26.10":
|
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.18.9", "@babel/core@^7.21.3", "@babel/core@^7.26.10":
|
||||||
version "7.27.1"
|
version "7.27.1"
|
||||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz"
|
resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz"
|
||||||
integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==
|
integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==
|
||||||
@@ -176,7 +176,7 @@
|
|||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.26.0", "@babel/types@^7.27.1":
|
"@babel/types@^7.0.0", "@babel/types@^7.18.9", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.26.0", "@babel/types@^7.27.1":
|
||||||
version "7.27.1"
|
version "7.27.1"
|
||||||
resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz"
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz"
|
||||||
integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==
|
integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==
|
||||||
@@ -222,6 +222,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz"
|
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz"
|
||||||
integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==
|
integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==
|
||||||
|
|
||||||
|
"@dimforge/rapier3d-compat@^0.12.0":
|
||||||
|
version "0.12.0"
|
||||||
|
resolved "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz"
|
||||||
|
integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==
|
||||||
|
|
||||||
"@dual-bundle/import-meta-resolve@^4.1.0":
|
"@dual-bundle/import-meta-resolve@^4.1.0":
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz"
|
resolved "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz"
|
||||||
@@ -510,7 +515,7 @@
|
|||||||
use-sync-external-store "^1.4.0"
|
use-sync-external-store "^1.4.0"
|
||||||
zustand "^5.0.3"
|
zustand "^5.0.3"
|
||||||
|
|
||||||
"@rollup/pluginutils@^5.0.2":
|
"@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.1.3":
|
||||||
version "5.1.4"
|
version "5.1.4"
|
||||||
resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz"
|
resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz"
|
||||||
integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
|
integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
|
||||||
@@ -624,6 +629,89 @@
|
|||||||
resolved "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.12.tgz"
|
resolved "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.12.tgz"
|
||||||
integrity sha512-6VjZg8HJ2Op7+KV7ihJpYrDnFtd9D1jrQnUS8LckcpuBXrIEbaut5+34ObY8ssQnSqkk2GwIZBBBQYQBCVvkOw==
|
integrity sha512-6VjZg8HJ2Op7+KV7ihJpYrDnFtd9D1jrQnUS8LckcpuBXrIEbaut5+34ObY8ssQnSqkk2GwIZBBBQYQBCVvkOw==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-add-jsx-attribute@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz"
|
||||||
|
integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-remove-jsx-attribute@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz"
|
||||||
|
integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz"
|
||||||
|
integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz"
|
||||||
|
integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-svg-dynamic-title@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz"
|
||||||
|
integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-svg-em-dimensions@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz"
|
||||||
|
integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-transform-react-native-svg@8.1.0":
|
||||||
|
version "8.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz"
|
||||||
|
integrity sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==
|
||||||
|
|
||||||
|
"@svgr/babel-plugin-transform-svg-component@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz"
|
||||||
|
integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==
|
||||||
|
|
||||||
|
"@svgr/babel-preset@8.1.0":
|
||||||
|
version "8.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz"
|
||||||
|
integrity sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==
|
||||||
|
dependencies:
|
||||||
|
"@svgr/babel-plugin-add-jsx-attribute" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-remove-jsx-attribute" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-svg-dynamic-title" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-svg-em-dimensions" "8.0.0"
|
||||||
|
"@svgr/babel-plugin-transform-react-native-svg" "8.1.0"
|
||||||
|
"@svgr/babel-plugin-transform-svg-component" "8.0.0"
|
||||||
|
|
||||||
|
"@svgr/core@*", "@svgr/core@^8.1.0":
|
||||||
|
version "8.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz"
|
||||||
|
integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.21.3"
|
||||||
|
"@svgr/babel-preset" "8.1.0"
|
||||||
|
camelcase "^6.2.0"
|
||||||
|
cosmiconfig "^8.1.3"
|
||||||
|
snake-case "^3.0.4"
|
||||||
|
|
||||||
|
"@svgr/hast-util-to-babel-ast@8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz"
|
||||||
|
integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.21.3"
|
||||||
|
entities "^4.4.0"
|
||||||
|
|
||||||
|
"@svgr/plugin-jsx@^8.1.0":
|
||||||
|
version "8.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz"
|
||||||
|
integrity sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.21.3"
|
||||||
|
"@svgr/babel-preset" "8.1.0"
|
||||||
|
"@svgr/hast-util-to-babel-ast" "8.0.0"
|
||||||
|
svg-parser "^2.0.4"
|
||||||
|
|
||||||
"@tabler/icons-react@^3.31.0":
|
"@tabler/icons-react@^3.31.0":
|
||||||
version "3.31.0"
|
version "3.31.0"
|
||||||
resolved "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.31.0.tgz"
|
resolved "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.31.0.tgz"
|
||||||
@@ -631,7 +719,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@tabler/icons" "3.31.0"
|
"@tabler/icons" "3.31.0"
|
||||||
|
|
||||||
"@tabler/icons@3.31.0":
|
"@tabler/icons@^3.31.0", "@tabler/icons@3.31.0":
|
||||||
version "3.31.0"
|
version "3.31.0"
|
||||||
resolved "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz"
|
resolved "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz"
|
||||||
integrity sha512-dblAdeKY3+GA1U+Q9eziZ0ooVlZMHsE8dqP0RkwvRtEsAULoKOYaCUOcJ4oW1DjWegdxk++UAt2SlQVnmeHv+g==
|
integrity sha512-dblAdeKY3+GA1U+Q9eziZ0ooVlZMHsE8dqP0RkwvRtEsAULoKOYaCUOcJ4oW1DjWegdxk++UAt2SlQVnmeHv+g==
|
||||||
@@ -675,6 +763,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz"
|
resolved "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz"
|
||||||
integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==
|
integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==
|
||||||
|
|
||||||
|
"@tweenjs/tween.js@~23.1.3":
|
||||||
|
version "23.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz"
|
||||||
|
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
|
||||||
|
|
||||||
"@types/aria-query@^5.0.1":
|
"@types/aria-query@^5.0.1":
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
|
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
|
||||||
@@ -757,6 +850,24 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz"
|
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz"
|
||||||
integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==
|
integrity sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==
|
||||||
|
|
||||||
|
"@types/stats.js@*":
|
||||||
|
version "0.17.4"
|
||||||
|
resolved "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz"
|
||||||
|
integrity sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==
|
||||||
|
|
||||||
|
"@types/three@^0.176.0":
|
||||||
|
version "0.176.0"
|
||||||
|
resolved "https://registry.npmjs.org/@types/three/-/three-0.176.0.tgz"
|
||||||
|
integrity sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==
|
||||||
|
dependencies:
|
||||||
|
"@dimforge/rapier3d-compat" "^0.12.0"
|
||||||
|
"@tweenjs/tween.js" "~23.1.3"
|
||||||
|
"@types/stats.js" "*"
|
||||||
|
"@types/webxr" "*"
|
||||||
|
"@webgpu/types" "*"
|
||||||
|
fflate "~0.8.2"
|
||||||
|
meshoptimizer "~0.18.1"
|
||||||
|
|
||||||
"@types/webxr@*":
|
"@types/webxr@*":
|
||||||
version "0.5.22"
|
version "0.5.22"
|
||||||
resolved "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz"
|
resolved "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz"
|
||||||
@@ -913,6 +1024,11 @@
|
|||||||
loupe "^3.1.3"
|
loupe "^3.1.3"
|
||||||
tinyrainbow "^2.0.0"
|
tinyrainbow "^2.0.0"
|
||||||
|
|
||||||
|
"@webgpu/types@*":
|
||||||
|
version "0.1.60"
|
||||||
|
resolved "https://registry.npmjs.org/@webgpu/types/-/types-0.1.60.tgz"
|
||||||
|
integrity sha512-8B/tdfRFKdrnejqmvq95ogp8tf52oZ51p3f4QD5m5Paey/qlX4Rhhy5Y8tgFMi7Ms70HzcMMw3EQjH/jdhTwlA==
|
||||||
|
|
||||||
accepts@^2.0.0:
|
accepts@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz"
|
||||||
@@ -1108,6 +1224,11 @@ async-function@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz"
|
||||||
integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==
|
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:
|
available-typed-arrays@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
|
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
|
||||||
@@ -1120,6 +1241,15 @@ axe-core@^4.10.0:
|
|||||||
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz"
|
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz"
|
||||||
integrity sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==
|
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:
|
axobject-query@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz"
|
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz"
|
||||||
@@ -1261,6 +1391,11 @@ camelcase-css@^2.0.1:
|
|||||||
resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz"
|
||||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||||
|
|
||||||
|
camelcase@^6.2.0:
|
||||||
|
version "6.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
|
||||||
|
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001716:
|
caniuse-lite@^1.0.30001716:
|
||||||
version "1.0.30001717"
|
version "1.0.30001717"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz"
|
||||||
@@ -1298,6 +1433,11 @@ check-error@^2.1.1:
|
|||||||
resolved "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz"
|
resolved "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz"
|
||||||
integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==
|
integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==
|
||||||
|
|
||||||
|
clsx@^1.1.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz"
|
||||||
|
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||||
|
|
||||||
clsx@^2.1.1:
|
clsx@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
|
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
|
||||||
@@ -1320,6 +1460,13 @@ colord@^2.9.3:
|
|||||||
resolved "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz"
|
resolved "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz"
|
||||||
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
|
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:
|
concat-map@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
||||||
@@ -1365,6 +1512,16 @@ cors@^2.8.5:
|
|||||||
object-assign "^4"
|
object-assign "^4"
|
||||||
vary "^1"
|
vary "^1"
|
||||||
|
|
||||||
|
cosmiconfig@^8.1.3:
|
||||||
|
version "8.3.6"
|
||||||
|
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz"
|
||||||
|
integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==
|
||||||
|
dependencies:
|
||||||
|
import-fresh "^3.3.0"
|
||||||
|
js-yaml "^4.1.0"
|
||||||
|
parse-json "^5.2.0"
|
||||||
|
path-type "^4.0.0"
|
||||||
|
|
||||||
cosmiconfig@^9.0.0:
|
cosmiconfig@^9.0.0:
|
||||||
version "9.0.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz"
|
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz"
|
||||||
@@ -1505,6 +1662,11 @@ define-properties@^1.1.3, define-properties@^1.2.1:
|
|||||||
has-property-descriptors "^1.0.0"
|
has-property-descriptors "^1.0.0"
|
||||||
object-keys "^1.1.1"
|
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:
|
depd@^2.0.0, depd@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
|
||||||
@@ -1551,6 +1713,14 @@ dom-accessibility-api@^0.6.3:
|
|||||||
resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz"
|
resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz"
|
||||||
integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==
|
integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==
|
||||||
|
|
||||||
|
dot-case@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz"
|
||||||
|
integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
|
||||||
|
dependencies:
|
||||||
|
no-case "^3.0.4"
|
||||||
|
tslib "^2.0.3"
|
||||||
|
|
||||||
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz"
|
resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz"
|
||||||
@@ -1590,6 +1760,11 @@ encodeurl@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz"
|
||||||
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
||||||
|
|
||||||
|
entities@^4.4.0:
|
||||||
|
version "4.5.0"
|
||||||
|
resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz"
|
||||||
|
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||||
|
|
||||||
entities@^6.0.0:
|
entities@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz"
|
resolved "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz"
|
||||||
@@ -2056,6 +2231,11 @@ fdir@^6.4.4:
|
|||||||
resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz"
|
resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz"
|
||||||
integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
|
integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
|
||||||
|
|
||||||
|
fflate@~0.8.2:
|
||||||
|
version "0.8.2"
|
||||||
|
resolved "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz"
|
||||||
|
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||||
|
|
||||||
file-entry-cache@^10.0.8:
|
file-entry-cache@^10.0.8:
|
||||||
version "10.0.8"
|
version "10.0.8"
|
||||||
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.8.tgz"
|
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.8.tgz"
|
||||||
@@ -2119,6 +2299,11 @@ flatted@^3.2.9, flatted@^3.3.3:
|
|||||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
||||||
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
|
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:
|
for-each@^0.3.3, for-each@^0.3.5:
|
||||||
version "0.3.5"
|
version "0.3.5"
|
||||||
resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz"
|
resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz"
|
||||||
@@ -2134,6 +2319,16 @@ foreground-child@^3.1.0:
|
|||||||
cross-spawn "^7.0.6"
|
cross-spawn "^7.0.6"
|
||||||
signal-exit "^4.0.1"
|
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:
|
forwarded@0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
|
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
|
||||||
@@ -2895,6 +3090,13 @@ loupe@^3.1.0, loupe@^3.1.3:
|
|||||||
resolved "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz"
|
resolved "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz"
|
||||||
integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==
|
integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==
|
||||||
|
|
||||||
|
lower-case@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz"
|
||||||
|
integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.3"
|
||||||
|
|
||||||
lru-cache@^10.2.0:
|
lru-cache@^10.2.0:
|
||||||
version "10.4.3"
|
version "10.4.3"
|
||||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
|
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
|
||||||
@@ -2983,6 +3185,11 @@ merge2@^1.3.0, merge2@^1.4.1:
|
|||||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
|
meshoptimizer@~0.18.1:
|
||||||
|
version "0.18.1"
|
||||||
|
resolved "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz"
|
||||||
|
integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==
|
||||||
|
|
||||||
micromatch@^4.0.8:
|
micromatch@^4.0.8:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
||||||
@@ -2996,6 +3203,18 @@ mime-db@^1.54.0:
|
|||||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
|
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
|
||||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
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:
|
mime-types@^3.0.0, mime-types@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz"
|
resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz"
|
||||||
@@ -3052,6 +3271,14 @@ negotiator@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
|
||||||
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
|
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
|
||||||
|
|
||||||
|
no-case@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz"
|
||||||
|
integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
|
||||||
|
dependencies:
|
||||||
|
lower-case "^2.0.2"
|
||||||
|
tslib "^2.0.3"
|
||||||
|
|
||||||
node-releases@^2.0.19:
|
node-releases@^2.0.19:
|
||||||
version "2.0.19"
|
version "2.0.19"
|
||||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz"
|
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz"
|
||||||
@@ -3412,6 +3639,11 @@ proxy-addr@^2.0.7:
|
|||||||
forwarded "0.2.0"
|
forwarded "0.2.0"
|
||||||
ipaddr.js "1.9.1"
|
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:
|
punycode@^2.1.0, punycode@^2.3.1:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
||||||
@@ -3444,6 +3676,11 @@ raw-body@^3.0.0:
|
|||||||
iconv-lite "0.6.3"
|
iconv-lite "0.6.3"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
re-resizable@6.11.2:
|
||||||
|
version "6.11.2"
|
||||||
|
resolved "https://registry.npmjs.org/re-resizable/-/re-resizable-6.11.2.tgz"
|
||||||
|
integrity sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A==
|
||||||
|
|
||||||
react-docgen-typescript@^2.2.2:
|
react-docgen-typescript@^2.2.2:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
resolved "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz"
|
resolved "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz"
|
||||||
@@ -3465,13 +3702,21 @@ react-docgen@^7.0.0:
|
|||||||
resolve "^1.22.1"
|
resolve "^1.22.1"
|
||||||
strip-indent "^4.0.0"
|
strip-indent "^4.0.0"
|
||||||
|
|
||||||
"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.x || ^19.x", react-dom@^19.0.0, react-dom@^19.1.0, react-dom@>=16.13, react-dom@>=16.8.0, react-dom@>=18:
|
"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.x || ^19.x", react-dom@^19.0.0, react-dom@^19.1.0, "react-dom@>= 16.3.0", react-dom@>=16.13, react-dom@>=16.3.0, react-dom@>=16.8.0, react-dom@>=18:
|
||||||
version "19.1.0"
|
version "19.1.0"
|
||||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz"
|
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz"
|
||||||
integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==
|
integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==
|
||||||
dependencies:
|
dependencies:
|
||||||
scheduler "^0.26.0"
|
scheduler "^0.26.0"
|
||||||
|
|
||||||
|
react-draggable@4.4.6:
|
||||||
|
version "4.4.6"
|
||||||
|
resolved "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz"
|
||||||
|
integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==
|
||||||
|
dependencies:
|
||||||
|
clsx "^1.1.1"
|
||||||
|
prop-types "^15.8.1"
|
||||||
|
|
||||||
react-is@^16.13.1:
|
react-is@^16.13.1:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
@@ -3518,6 +3763,15 @@ react-remove-scroll@^2.6.2:
|
|||||||
use-callback-ref "^1.3.3"
|
use-callback-ref "^1.3.3"
|
||||||
use-sidecar "^1.1.3"
|
use-sidecar "^1.1.3"
|
||||||
|
|
||||||
|
react-rnd@^10.5.2:
|
||||||
|
version "10.5.2"
|
||||||
|
resolved "https://registry.npmjs.org/react-rnd/-/react-rnd-10.5.2.tgz"
|
||||||
|
integrity sha512-0Tm4x7k7pfHf2snewJA8x7Nwgt3LV+58MVEWOVsFjk51eYruFEa6Wy7BNdxt4/lH0wIRsu7Gm3KjSXY2w7YaNw==
|
||||||
|
dependencies:
|
||||||
|
re-resizable "6.11.2"
|
||||||
|
react-draggable "4.4.6"
|
||||||
|
tslib "2.6.2"
|
||||||
|
|
||||||
react-router-dom@^7.4.0:
|
react-router-dom@^7.4.0:
|
||||||
version "7.5.3"
|
version "7.5.3"
|
||||||
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.3.tgz"
|
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.3.tgz"
|
||||||
@@ -3556,7 +3810,7 @@ react-use-measure@^2.1.7:
|
|||||||
resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz"
|
resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz"
|
||||||
integrity sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==
|
integrity sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==
|
||||||
|
|
||||||
"react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react@^18.0.0 || ^19.0.0", "react@^18.x || ^19.x", react@^19.0.0, react@^19.1.0, "react@>= 16", react@>=16.13, react@>=16.8.0, react@>=17.0, react@>=18, react@>=18.0.0:
|
"react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react@^18.0.0 || ^19.0.0", "react@^18.x || ^19.x", react@^19.0.0, react@^19.1.0, "react@>= 16", "react@>= 16.3.0", react@>=16.13, react@>=16.3.0, react@>=16.8.0, react@>=17.0, react@>=18, react@>=18.0.0:
|
||||||
version "19.1.0"
|
version "19.1.0"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz"
|
||||||
integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
|
integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
|
||||||
@@ -3905,6 +4159,14 @@ slice-ansi@^4.0.0:
|
|||||||
astral-regex "^2.0.0"
|
astral-regex "^2.0.0"
|
||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
|
|
||||||
|
snake-case@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz"
|
||||||
|
integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
|
||||||
|
dependencies:
|
||||||
|
dot-case "^3.0.4"
|
||||||
|
tslib "^2.0.3"
|
||||||
|
|
||||||
source-map-js@^1.0.1, source-map-js@^1.2.1:
|
source-map-js@^1.0.1, source-map-js@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
||||||
@@ -4217,6 +4479,11 @@ suspend-react@^0.1.3:
|
|||||||
resolved "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz"
|
resolved "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz"
|
||||||
integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==
|
integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==
|
||||||
|
|
||||||
|
svg-parser@^2.0.4:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz"
|
||||||
|
integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
|
||||||
|
|
||||||
svg-tags@^1.0.0:
|
svg-tags@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz"
|
||||||
@@ -4348,11 +4615,16 @@ tsconfig-paths@^4.2.0:
|
|||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0:
|
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
|
|
||||||
|
tslib@2.6.2:
|
||||||
|
version "2.6.2"
|
||||||
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
|
||||||
|
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||||
|
|
||||||
turbo-stream@2.4.0:
|
turbo-stream@2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz"
|
resolved "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz"
|
||||||
@@ -4550,6 +4822,15 @@ vite-node@3.1.3:
|
|||||||
pathe "^2.0.3"
|
pathe "^2.0.3"
|
||||||
vite "^5.0.0 || ^6.0.0"
|
vite "^5.0.0 || ^6.0.0"
|
||||||
|
|
||||||
|
vite-plugin-svgr@^4.3.0:
|
||||||
|
version "4.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz"
|
||||||
|
integrity sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==
|
||||||
|
dependencies:
|
||||||
|
"@rollup/pluginutils" "^5.1.3"
|
||||||
|
"@svgr/core" "^8.1.0"
|
||||||
|
"@svgr/plugin-jsx" "^8.1.0"
|
||||||
|
|
||||||
vite-tsconfig-paths@^5.1.4:
|
vite-tsconfig-paths@^5.1.4:
|
||||||
version "5.1.4"
|
version "5.1.4"
|
||||||
resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz"
|
resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz"
|
||||||
@@ -4559,7 +4840,7 @@ vite-tsconfig-paths@^5.1.4:
|
|||||||
globrex "^0.1.2"
|
globrex "^0.1.2"
|
||||||
tsconfck "^3.0.3"
|
tsconfck "^3.0.3"
|
||||||
|
|
||||||
vite@*, "vite@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "vite@^4.0.0 || ^5.0.0 || ^6.0.0", "vite@^4.2.0 || ^5.0.0 || ^6.0.0", "vite@^5.0.0 || ^6.0.0", vite@^6.2.2:
|
vite@*, "vite@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "vite@^4.0.0 || ^5.0.0 || ^6.0.0", "vite@^4.2.0 || ^5.0.0 || ^6.0.0", "vite@^5.0.0 || ^6.0.0", vite@^6.2.2, vite@>=2.6.0:
|
||||||
version "6.3.5"
|
version "6.3.5"
|
||||||
resolved "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz"
|
resolved "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz"
|
||||||
integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==
|
integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==
|
||||||
|
|||||||
-122
@@ -1,122 +0,0 @@
|
|||||||
from llms.Modelos.Base_model import ModeloABC
|
|
||||||
from llms.Memory.Base_MemoryConv import MemoryConvABC
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from typing import Optional, List, Union
|
|
||||||
|
|
||||||
|
|
||||||
class AgenteAI:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
modelo: ModeloABC,
|
|
||||||
nombre: str,
|
|
||||||
descripcion: str,
|
|
||||||
system_prompt: str, # <- pertenece al agente
|
|
||||||
rol: str,
|
|
||||||
objetivos: List[str],
|
|
||||||
memoria: Optional[MemoryConvABC] = None,
|
|
||||||
version: str = "1.0.0",
|
|
||||||
tools: Optional[List] = None,
|
|
||||||
output_schema: Optional[dict] = None, # <- nuevo parámetro
|
|
||||||
):
|
|
||||||
self.modelo = modelo
|
|
||||||
self.memoria = memoria
|
|
||||||
self.tools = tools or []
|
|
||||||
self.output_schema = output_schema
|
|
||||||
|
|
||||||
self.nombre = nombre
|
|
||||||
self.descripcion = descripcion
|
|
||||||
self.system_prompt = system_prompt
|
|
||||||
self.rol = rol
|
|
||||||
self.objetivos = objetivos
|
|
||||||
self.version = version
|
|
||||||
|
|
||||||
self.created_at = datetime.now()
|
|
||||||
self.updated_at = self.created_at
|
|
||||||
self.numero_interacciones = 0
|
|
||||||
|
|
||||||
def actualizar_configuracion(self, **kwargs):
|
|
||||||
for clave, valor in kwargs.items():
|
|
||||||
if hasattr(self, clave):
|
|
||||||
setattr(self, clave, valor)
|
|
||||||
self.updated_at = datetime.now()
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
|
||||||
def full_system_prompt(self) -> str:
|
|
||||||
partes = [
|
|
||||||
f"Tu nombre es: {self.nombre}",
|
|
||||||
f"Tu descripción: {self.descripcion}",
|
|
||||||
f"Tu Rol: {self.rol}",
|
|
||||||
f"Tus Objetivos: {', '.join(self.objetivos)}",
|
|
||||||
""
|
|
||||||
]
|
|
||||||
|
|
||||||
# Incluir herramientas disponibles
|
|
||||||
herramientas = self._obtener_descripcion_tools()
|
|
||||||
if herramientas:
|
|
||||||
partes.append("Estas son tus herramientas disponibles:\n")
|
|
||||||
partes.extend(herramientas)
|
|
||||||
partes.append("Úsalas cuando creas oportuno.\n")
|
|
||||||
|
|
||||||
partes.append(self.system_prompt)
|
|
||||||
|
|
||||||
if self.output_schema:
|
|
||||||
partes.append(
|
|
||||||
"SIEMPRE formatea la respuesta final siguiendo estrictamente el siguiente esquema JSON:"
|
|
||||||
)
|
|
||||||
partes.append(f"```json\n{self.output_schema}\n```")
|
|
||||||
|
|
||||||
return "\n".join(partes)
|
|
||||||
|
|
||||||
def _obtener_descripcion_tools(self) -> List[str]:
|
|
||||||
"""
|
|
||||||
Devuelve una lista de strings con el nombre y descripción de cada herramienta
|
|
||||||
recogida desde los servidores MCP conectados.
|
|
||||||
"""
|
|
||||||
descripciones = []
|
|
||||||
if not hasattr(self, "mcp_servers"):
|
|
||||||
return descripciones
|
|
||||||
|
|
||||||
for server in self.mcp_servers:
|
|
||||||
if hasattr(server, "tools") and server.tools:
|
|
||||||
for tool in server.tools:
|
|
||||||
# tool puede ser string o dict, depende cómo lo expongas
|
|
||||||
if isinstance(tool, str):
|
|
||||||
descripciones.append(f"- {tool}: [sin descripción]")
|
|
||||||
elif isinstance(tool, dict):
|
|
||||||
nombre = tool.get("name", "¿?")
|
|
||||||
descripcion = tool.get("description", "[sin descripción]")
|
|
||||||
descripciones.append(f"- {nombre}: {descripcion}")
|
|
||||||
elif hasattr(tool, "name"):
|
|
||||||
descripcion = getattr(tool, "description", "[sin descripción]")
|
|
||||||
descripciones.append(f"- {tool.name}: {descripcion}")
|
|
||||||
return descripciones
|
|
||||||
|
|
||||||
async def interactuar(self, prompt: str) -> str:
|
|
||||||
if not self.modelo:
|
|
||||||
raise ValueError("El agente no tiene un modelo asignado.")
|
|
||||||
|
|
||||||
historial = []
|
|
||||||
if self.memoria:
|
|
||||||
historial = self.memoria.cargar_historial_chat()
|
|
||||||
|
|
||||||
contexto = historial + [{"role": "user", "content": prompt}]
|
|
||||||
prompt_final = self._formatear_prompt(contexto)
|
|
||||||
|
|
||||||
# Espera la respuesta del modelo de forma asíncrona
|
|
||||||
respuesta = await self.modelo.responder(
|
|
||||||
prompt=prompt_final,
|
|
||||||
system_prompt=self.full_system_prompt
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.memoria:
|
|
||||||
self.memoria.guardar_turno("user", prompt)
|
|
||||||
self.memoria.guardar_turno("assistant", respuesta)
|
|
||||||
|
|
||||||
self.numero_interacciones += 1
|
|
||||||
self.updated_at = datetime.now()
|
|
||||||
return respuesta
|
|
||||||
|
|
||||||
def _formatear_prompt(self, mensajes: List[dict]) -> str:
|
|
||||||
return "\n".join([f"{msg['role']}: {msg['content']}" for msg in mensajes])
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import os
|
|
||||||
from typing import Optional, List, Dict
|
|
||||||
from contextlib import AsyncExitStack
|
|
||||||
from mcp import ClientSession, StdioServerParameters
|
|
||||||
from mcp.client.stdio import stdio_client
|
|
||||||
from mcp.types import Tool
|
|
||||||
|
|
||||||
class MCPStdioServer:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
command: str,
|
|
||||||
args: List[str],
|
|
||||||
env: Optional[Dict[str, str]] = None
|
|
||||||
):
|
|
||||||
self.name = name
|
|
||||||
self.command = command
|
|
||||||
self.args = args
|
|
||||||
self.env = env or os.environ.copy()
|
|
||||||
self.exit_stack = AsyncExitStack()
|
|
||||||
self.session: Optional[ClientSession] = None
|
|
||||||
self.tools: List[Tool] = []
|
|
||||||
|
|
||||||
async def start(self):
|
|
||||||
# Configurar el bucle de eventos Proactor en Windows si es necesario
|
|
||||||
if os.name == "nt":
|
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
|
||||||
|
|
||||||
server_params = StdioServerParameters(
|
|
||||||
command=self.command,
|
|
||||||
args=self.args,
|
|
||||||
env=self.env
|
|
||||||
)
|
|
||||||
|
|
||||||
# Iniciar el transporte y establecer la sesión
|
|
||||||
stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
|
|
||||||
read, write = stdio_transport
|
|
||||||
|
|
||||||
self.session = await self.exit_stack.enter_async_context(ClientSession(read, write))
|
|
||||||
await self.session.initialize()
|
|
||||||
response = await self.session.list_tools()
|
|
||||||
self.tools = response.tools
|
|
||||||
|
|
||||||
if self.tools:
|
|
||||||
print(f"[{self.name}] Servidor iniciado con herramientas:")
|
|
||||||
for tool in self.tools:
|
|
||||||
nombre = getattr(tool, "name", "[sin nombre]")
|
|
||||||
descripcion = getattr(tool, "description", "[sin descripción]")
|
|
||||||
print(f" - {nombre} - {descripcion}")
|
|
||||||
else:
|
|
||||||
print(f"[{self.name}] Servidor iniciado, pero no se detectaron herramientas.")
|
|
||||||
|
|
||||||
async def call_tool(self, tool_name: str, arguments: Dict):
|
|
||||||
if not self.session:
|
|
||||||
raise RuntimeError("La sesión no está inicializada.")
|
|
||||||
result = await self.session.call_tool(tool_name, arguments)
|
|
||||||
return result.content
|
|
||||||
|
|
||||||
def get_tool_names(self) -> List[str]:
|
|
||||||
return [tool.name for tool in self.tools]
|
|
||||||
|
|
||||||
async def stop(self):
|
|
||||||
await self.exit_stack.aclose()
|
|
||||||
print(f"[{self.name}] Servidor detenido.")
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
from llms.Modelos.Base_model import ModeloABC
|
|
||||||
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
|
||||||
|
|
||||||
class ModeloOpenAI(ModeloABC):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
cliente: OpenAICliente,
|
|
||||||
model: str = "gpt-4o",
|
|
||||||
temperature: float = 0.7,
|
|
||||||
top_p: float = 1.0,
|
|
||||||
top_k: int = None,
|
|
||||||
frecuencia_penalizacion: float = 0.0,
|
|
||||||
num_tokens_maximos: int = 512,
|
|
||||||
use_legacy: bool = False
|
|
||||||
):
|
|
||||||
super().__init__(
|
|
||||||
model=model,
|
|
||||||
temperature=temperature,
|
|
||||||
top_p=top_p,
|
|
||||||
top_k=top_k,
|
|
||||||
frecuencia_penalizacion=frecuencia_penalizacion,
|
|
||||||
num_tokens_maximos=num_tokens_maximos
|
|
||||||
)
|
|
||||||
self.cliente = cliente
|
|
||||||
self.use_legacy = use_legacy
|
|
||||||
|
|
||||||
async def responder(self, prompt: str, system_prompt: str = "", **kwargs) -> str:
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
if self.use_legacy:
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
respuesta = await loop.run_in_executor(
|
|
||||||
None,
|
|
||||||
lambda: self.cliente.completion(
|
|
||||||
model=self.model,
|
|
||||||
prompt=prompt,
|
|
||||||
temperature=self.temperature,
|
|
||||||
top_p=self.top_p,
|
|
||||||
max_tokens=self.num_tokens_maximos,
|
|
||||||
frequency_penalty=self.frecuencia_penalizacion,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return respuesta.choices[0].text.strip()
|
|
||||||
else:
|
|
||||||
messages = []
|
|
||||||
if system_prompt:
|
|
||||||
messages.append({"role": "system", "content": system_prompt})
|
|
||||||
messages.append({"role": "user", "content": prompt})
|
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
respuesta = await loop.run_in_executor(
|
|
||||||
None,
|
|
||||||
lambda: self.cliente.chat_completion(
|
|
||||||
model=self.model,
|
|
||||||
messages=messages,
|
|
||||||
temperature=self.temperature,
|
|
||||||
top_p=self.top_p,
|
|
||||||
max_tokens=self.num_tokens_maximos,
|
|
||||||
frequency_penalty=self.frecuencia_penalizacion,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return respuesta.choices[0].message.content
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import os
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from sqlalchemy import Column, Integer, String, Float, Boolean
|
|
||||||
|
|
||||||
from src.ConexionSql.Base_conexion import ConexionBase
|
|
||||||
from src.base import Base
|
|
||||||
from llms.Modelos.Openai_model import ModeloOpenAI # Clase real de lógica
|
|
||||||
|
|
||||||
# ----------------------
|
|
||||||
# Cargar clave maestra
|
|
||||||
# ----------------------
|
|
||||||
from entrypoint import ENV_PATH
|
|
||||||
load_dotenv(ENV_PATH)
|
|
||||||
pssword = os.getenv('MASTER_PASSWORD')
|
|
||||||
if pssword is None:
|
|
||||||
raise ValueError("MASTER_PASSWORD no está definida en el archivo .env")
|
|
||||||
|
|
||||||
# ----------------------
|
|
||||||
# MODELO (SQLAlchemy)
|
|
||||||
# ----------------------
|
|
||||||
|
|
||||||
class ModeloOpenAIConfigModel(Base):
|
|
||||||
__tablename__ = 'modelo_openai_configs'
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
model = Column(String, nullable=False)
|
|
||||||
temperature = Column(Float, default=0.7)
|
|
||||||
top_p = Column(Float, default=1.0)
|
|
||||||
top_k = Column(Integer, nullable=True)
|
|
||||||
frecuencia_penalizacion = Column(Float, default=0.0)
|
|
||||||
num_tokens_maximos = Column(Integer, default=512)
|
|
||||||
use_legacy = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
# ----------------------
|
|
||||||
# MAPPER
|
|
||||||
# ----------------------
|
|
||||||
|
|
||||||
class ModeloOpenAIConfigMapper:
|
|
||||||
@staticmethod
|
|
||||||
def to_dict(obj: ModeloOpenAI) -> dict:
|
|
||||||
return {
|
|
||||||
"model": obj.model,
|
|
||||||
"temperature": obj.temperature,
|
|
||||||
"top_p": obj.top_p,
|
|
||||||
"top_k": obj.top_k,
|
|
||||||
"frecuencia_penalizacion": obj.frecuencia_penalizacion,
|
|
||||||
"num_tokens_maximos": obj.num_tokens_maximos,
|
|
||||||
"use_legacy": obj.use_legacy
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_model(model: ModeloOpenAIConfigModel, cliente: object) -> ModeloOpenAI:
|
|
||||||
return ModeloOpenAI(
|
|
||||||
cliente=cliente,
|
|
||||||
model=model.model,
|
|
||||||
temperature=model.temperature,
|
|
||||||
top_p=model.top_p,
|
|
||||||
top_k=model.top_k,
|
|
||||||
frecuencia_penalizacion=model.frecuencia_penalizacion,
|
|
||||||
num_tokens_maximos=model.num_tokens_maximos,
|
|
||||||
use_legacy=model.use_legacy
|
|
||||||
)
|
|
||||||
|
|
||||||
# ----------------------
|
|
||||||
# REPO
|
|
||||||
# ----------------------
|
|
||||||
|
|
||||||
class ModeloOpenAIConfigRepo:
|
|
||||||
def __init__(self, conexion: ConexionBase, cliente: object):
|
|
||||||
self.session = conexion.get_session()
|
|
||||||
self.cliente = cliente # Necesario para crear ModeloOpenAI
|
|
||||||
|
|
||||||
def add(self, config: ModeloOpenAI) -> int:
|
|
||||||
data = ModeloOpenAIConfigMapper.to_dict(config)
|
|
||||||
model = ModeloOpenAIConfigModel(**data)
|
|
||||||
self.session.add(model)
|
|
||||||
self.session.commit()
|
|
||||||
return model.id
|
|
||||||
|
|
||||||
def get_by_id(self, id_: int) -> ModeloOpenAI | None:
|
|
||||||
model = self.session.get(ModeloOpenAIConfigModel, id_)
|
|
||||||
return ModeloOpenAIConfigMapper.from_model(model, self.cliente) if model else None
|
|
||||||
|
|
||||||
def get_all(self) -> list[ModeloOpenAI]:
|
|
||||||
models = self.session.query(ModeloOpenAIConfigModel).all()
|
|
||||||
return [ModeloOpenAIConfigMapper.from_model(m, self.cliente) for m in models]
|
|
||||||
@@ -1,11 +1,34 @@
|
|||||||
# main.py
|
# main.py
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import uvicorn
|
||||||
from entrypoint.init_db import init_db
|
from entrypoint.init_db import init_db
|
||||||
|
|
||||||
|
from backend.main import app as fastapi_app
|
||||||
|
|
||||||
|
async def main_async():
|
||||||
|
# Inicia tareas de fondo controladas desde aquí
|
||||||
|
print("🔄 Lanzando tareas en segundo plano...")
|
||||||
|
tareas = []
|
||||||
|
|
||||||
|
# Configura y lanza el servidor FastAPI
|
||||||
|
print("🚀 Lanzando servidor FastAPI...")
|
||||||
|
config = uvicorn.Config(app=fastapi_app, host="0.0.0.0", port=8000, reload=True)
|
||||||
|
server = uvicorn.Server(config)
|
||||||
|
|
||||||
|
# Ejecuta servidor (bloqueante)
|
||||||
|
await server.serve()
|
||||||
|
|
||||||
|
# Cancela tareas si se cae el servidor
|
||||||
|
for task in tareas:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Aquí puedes colocar lógica adicional de arranque si la tienes
|
print("🛠️ Inicializando base de datos...")
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
print("✅ Iniciando sistema...")
|
||||||
|
asyncio.run(main_async())
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
@@ -2,18 +2,10 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 1,
|
||||||
"id": "26aa8e2b",
|
"id": "26aa8e2b",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"✅ Credencial: Credencial_enmanuel\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"from src.ApiKeys.openai_apikey import OpenAICredencial\n",
|
"from src.ApiKeys.openai_apikey import OpenAICredencial\n",
|
||||||
"from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo\n",
|
"from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo\n",
|
||||||
@@ -24,14 +16,64 @@
|
|||||||
"conexion_admin = PostgresConexion(db_credencial)\n",
|
"conexion_admin = PostgresConexion(db_credencial)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# 3. Guardar la credencial en la base de datos\n",
|
"# 3. Guardar la credencial en la base de datos\n",
|
||||||
"repo = OpenAICredencialRepo(conexion_admin)\n",
|
"repo = OpenAICredencialRepo(conexion_admin)\n"
|
||||||
"credencial_openai = repo.get_by_id(1)\n",
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "4c232ecd",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"'OPAK20250513-61b29978b7604031014'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 2,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"apikey_gpt = OpenAICredencial(titulo=\"Credencial_enmanuel_gpt\",\n",
|
||||||
|
" api_key=\"\")\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"repo.add(apikey_gpt)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "32552452",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"✅ Credencial: Credencial_enmanuel_gpt\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"credencial_openai = repo.get_by_id('OPAK20250513-61b29978b7604031014')\n",
|
||||||
"print(f\"✅ Credencial: {credencial_openai.titulo}\")"
|
"print(f\"✅ Credencial: {credencial_openai.titulo}\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
|
"id": "7464fa65",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
"id": "e5b665a6",
|
"id": "e5b665a6",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -60,12 +102,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": null,
|
||||||
"id": "ada431b7",
|
"id": "ada431b7",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from llms.Modelos.Openai_model import ModeloOpenAI\n",
|
"from src.Llms.Modelos.Openai_model import ModeloOpenAI\n",
|
||||||
"\n",
|
"\n",
|
||||||
"modelo = ModeloOpenAI(\n",
|
"modelo = ModeloOpenAI(\n",
|
||||||
" cliente=cliente,\n",
|
" cliente=cliente,\n",
|
||||||
@@ -98,12 +140,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 5,
|
"execution_count": null,
|
||||||
"id": "ce8628d4",
|
"id": "ce8628d4",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from llms.Memory.postgres_MemoryConv import MemoryConvPostgres\n",
|
"from src.Llms.Memory.postgres_MemoryConv import MemoryConvPostgres\n",
|
||||||
"\n",
|
"\n",
|
||||||
"memoria = MemoryConvPostgres(\n",
|
"memoria = MemoryConvPostgres(\n",
|
||||||
" credencial=db_credencial,\n",
|
" credencial=db_credencial,\n",
|
||||||
@@ -114,29 +156,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 6,
|
"execution_count": null,
|
||||||
"id": "a25bc742",
|
"id": "a25bc742",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"```json\n",
|
|
||||||
"{\n",
|
|
||||||
" \"objeto_celeste\": \"Betelgeuse\",\n",
|
|
||||||
" \"tipo_objeto\": \"Supergigante Roja\",\n",
|
|
||||||
" \"respuesta_resumida\": \"Betelgeuse es una supergigante roja en la constelación de Orión que se volvió más tenue en 2019 debido a una gran eyección de material estelar y la formación de polvo.\",\n",
|
|
||||||
" \"respuesta_detallada\": \"Betelgeuse es una estrella supergigante roja localizada a unos 640 años luz en la constelación de Orión. A finales de 2019 y principios de 2020, Betelgeuse experimentó una notable disminución en su brillo que atrajo gran atención. Esta atenuación fue causada principalmente por una eyección masiva de gas desde la estrella, que al enfriarse, se condensó formando polvo estelar cerca de la estrella. Este polvo bloqueó parcialmente la luz de Betelgeuse, haciendo que pareciera más tenue desde la Tierra. Tal comportamiento no es inesperado en supergigantes rojas, que son estrellas en etapas avanzadas de evolución y pueden mostrar variaciones de brillo debido a pulsaciones internas y procesos de pérdida de masa.\",\n",
|
|
||||||
" \"contexto_observacional\": \"Betelgeuse es visible a simple vista en el cielo nocturno, especialmente durante el invierno en el hemisferio norte. Sus cambios de brillo fueron observados tanto por astrónomos aficionados como por profesionales usando telescopios.\",\n",
|
|
||||||
" \"referencias_relevantes\": [\"Evolución de las estrellas masivas y supergigantes rojas, Nature Astronomy (2020)\", \"Observaciones del Telescopio Espacial Hubble sobre Betelgeuse\"]\n",
|
|
||||||
"}\n",
|
|
||||||
"```\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"from llms.Agente import AgenteAI\n",
|
"from src.Llms.Agente import AgenteAI\n",
|
||||||
|
"import asyncio\n",
|
||||||
"\n",
|
"\n",
|
||||||
"output_schema = {\n",
|
"output_schema = {\n",
|
||||||
" \"objeto_celeste\": \"<nombre del objeto o fenómeno principal al que se refiere la respuesta, e.g., 'Júpiter', 'Vía Láctea', 'Supernova tipo Ia'>\",\n",
|
" \"objeto_celeste\": \"<nombre del objeto o fenómeno principal al que se refiere la respuesta, e.g., 'Júpiter', 'Vía Láctea', 'Supernova tipo Ia'>\",\n",
|
||||||
@@ -155,15 +181,14 @@
|
|||||||
" rol=\"astronomo\",\n",
|
" rol=\"astronomo\",\n",
|
||||||
" memoria=memoria,\n",
|
" memoria=memoria,\n",
|
||||||
" objetivos=[\"Responder preguntas sobre astronomía y astrofísica\", \"Proporcionar explicaciones detalladas y ejemplos numéricos\"],\n",
|
" objetivos=[\"Responder preguntas sobre astronomía y astrofísica\", \"Proporcionar explicaciones detalladas y ejemplos numéricos\"],\n",
|
||||||
" output_schema=output_schema\n",
|
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"respuesta = agente.interactuar(\n",
|
"# respuesta = await agente.interactuar(\n",
|
||||||
" prompt=\"¿Qué es Betelgeuse y por qué se volvió más tenue en 2019?\",\n",
|
"# prompt=\"¿Qué es Betelgeuse y por qué se volvió más tenue en 2019?\",\n",
|
||||||
")\n",
|
"# )\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(respuesta)"
|
"# print(respuesta)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -181,11 +206,7 @@
|
|||||||
"Tu Rol: astronomo\n",
|
"Tu Rol: astronomo\n",
|
||||||
"Tus Objetivos: Responder preguntas sobre astronomía y astrofísica, Proporcionar explicaciones detalladas y ejemplos numéricos\n",
|
"Tus Objetivos: Responder preguntas sobre astronomía y astrofísica, Proporcionar explicaciones detalladas y ejemplos numéricos\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Actúa como un experto en astronomía y astrofísica con experiencia académica y práctica en observación astronómica, física estelar, cosmología, mecánica orbital y análisis de datos astronómicos. Cuando respondas, utiliza lenguaje técnico pero accesible para alguien con conocimientos intermedios en física y matemáticas. Siempre que sea posible, incluye explicaciones detalladas, ejemplos numéricos y referencias a teorías o descubrimientos relevantes (por ejemplo, relatividad general, evolución estelar, espectroscopía, etc.). No simplifiques en exceso. Si la pregunta tiene múltiples dimensiones (como observacional y teórica), aborda todas. ¿Estás listo para empezar?\n",
|
"Actúa como un experto en astronomía y astrofísica con experiencia académica y práctica en observación astronómica, física estelar, cosmología, mecánica orbital y análisis de datos astronómicos. Cuando respondas, utiliza lenguaje técnico pero accesible para alguien con conocimientos intermedios en física y matemáticas. Siempre que sea posible, incluye explicaciones detalladas, ejemplos numéricos y referencias a teorías o descubrimientos relevantes (por ejemplo, relatividad general, evolución estelar, espectroscopía, etc.). No simplifiques en exceso. Si la pregunta tiene múltiples dimensiones (como observacional y teórica), aborda todas. ¿Estás listo para empezar?\n"
|
||||||
"SIEMPRE formatea la respuesta final siguiendo estrictamente el siguiente esquema JSON:\n",
|
|
||||||
"```json\n",
|
|
||||||
"{'objeto_celeste': \"<nombre del objeto o fenómeno principal al que se refiere la respuesta, e.g., 'Júpiter', 'Vía Láctea', 'Supernova tipo Ia'>\", 'tipo_objeto': '<clasificación general: planeta, estrella, galaxia, agujero negro, fenómeno cosmológico, etc.>', 'respuesta_resumida': '<resumen de máximo 3 líneas de la explicación>', 'respuesta_detallada': '<explicación extensa con base científica, observacional y teórica si aplica>', 'contexto_observacional': '<si es observable desde la Tierra, en qué condiciones o con qué instrumentos>', 'referencias_relevantes': ['<libros, papers, misiones espaciales o catálogos astronómicos relevantes>']}\n",
|
|
||||||
"```\n"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -195,36 +216,85 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 11,
|
"execution_count": 8,
|
||||||
"id": "07e3b6de",
|
"id": "07e3b6de",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# agente_con_herramientas = AgenteAI(\n",
|
||||||
|
"# modelo=modelo,\n",
|
||||||
|
"# nombre=\"Agente con herramientas\",\n",
|
||||||
|
"# descripcion=\"Un agente que puede usar herramientas\",\n",
|
||||||
|
"# system_prompt=\"Eres un asistente que puede usar herramientas para responder preguntas.\",\n",
|
||||||
|
"# rol=\"asistente\",\n",
|
||||||
|
"# memoria= memoria,\n",
|
||||||
|
"# objetivos=[\"Asistir al usuario en tareas complejas\", \"usar herramientas para obtener información adicional\"]\n",
|
||||||
|
"# # tools=\n",
|
||||||
|
"\n",
|
||||||
|
"# )\n",
|
||||||
|
"\n",
|
||||||
|
"# respuesta = agente_con_herramientas.interactuar(\n",
|
||||||
|
"# prompt=\"Hola como estas?\",\n",
|
||||||
|
"# )\n",
|
||||||
|
"\n",
|
||||||
|
"# print(respuesta)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 10,
|
||||||
|
"id": "5d9fc77e",
|
||||||
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"¡Hola! Estoy aquí para ayudarte con cualquier pregunta o tarea que tengas. ¿En qué puedo asistirte hoy?\n"
|
"Desde una perspectiva astronómica y cosmológica, \"de dónde venimos\" y \"a dónde vamos\" son preguntas profundas que tocan conceptos sobre el origen y el destino del Universo y de la humanidad dentro de él.\n",
|
||||||
|
"\n",
|
||||||
|
"**De dónde venimos:**\n",
|
||||||
|
"\n",
|
||||||
|
"1. **Origen del Universo**: La teoría más aceptada sobre el origen del Universo es el Big Bang, que propone que el Universo nació hace aproximadamente 13.8 mil millones de años a partir de una singularidad extremadamente caliente y densa. Desde entonces, ha estado expandiéndose y enfriándose, permitiendo la formación de partículas, átomos y eventualmente estrellas y galaxias.\n",
|
||||||
|
"\n",
|
||||||
|
"2. **Formación de elementos y planetas**: Las primeras generaciones de estrellas sintetizaron elementos pesados en sus núcleos y, al explotar como supernovas, dispersaron estos elementos al espacio, enriqueciendo el medio interestelar. Este material enriquecido permitió la formación de planetas como la Tierra.\n",
|
||||||
|
"\n",
|
||||||
|
"3. **Evolución de la Vida**: En la Tierra, los procesos químicos dieron lugar a organismos primitivos, los cuales evolucionaron a lo largo de miles de millones de años para dar lugar a la biodiversidad actual, incluyendo a los seres humanos.\n",
|
||||||
|
"\n",
|
||||||
|
"**A dónde vamos:**\n",
|
||||||
|
"\n",
|
||||||
|
"1. **Destinos individuales y colectivos**: A nivel personal y colectivo, los destinos humanos dependen de nuestra evolución tecnológica y social. Estamos explorando nuestro sistema solar e incluso considerando la colonización de otros planetas, como Marte.\n",
|
||||||
|
"\n",
|
||||||
|
"2. **Futuro del Universo**: El futuro del Universo dependerá de su composición y energía oscura. Dos posibles destinos son:\n",
|
||||||
|
"\n",
|
||||||
|
" - *Expansión infinita*: El Universo podría continuar expandiéndose indefinidamente, llevando a un futuro frío y oscuro conocido como muerte térmica, donde las estrellas se agoten y las galaxias se separen.\n",
|
||||||
|
"\n",
|
||||||
|
" - *Big Crunch o Big Rip*: Alternativamente, si la densidad del Universo es lo suficientemente alta, podría detenerse y comenzar a contraerse en un Big Crunch, o si la energía oscura desempeña un papel más caótico, experimentar un Big Rip, donde el Universo se desgarra.\n",
|
||||||
|
"\n",
|
||||||
|
"Estas fascinantes preguntas inspiran tanto la ciencia como la filosofía y nos estimulan a seguir explorando el cosmos para comprender nuestro lugar y destino en él. <FIN>\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"agente_con_herramientas = AgenteAI(\n",
|
"agente2 = AgenteAI(\n",
|
||||||
" modelo=modelo,\n",
|
" modelo=modelo,\n",
|
||||||
" nombre=\"Agente con herramientas\",\n",
|
" nombre=\"Experto en Astronomía\",\n",
|
||||||
" descripcion=\"Un agente que puede usar herramientas\",\n",
|
" descripcion=\"Un experto en astronomía que responde preguntas sobre el universo.\",\n",
|
||||||
" system_prompt=\"Eres un asistente que puede usar herramientas para responder preguntas.\",\n",
|
" system_prompt=\"Actúa como un experto en astronomía y astrofísica con experiencia académica y práctica en observación astronómica, física estelar, cosmología, mecánica orbital y análisis de datos astronómicos. Cuando respondas, utiliza lenguaje técnico pero accesible para alguien con conocimientos intermedios en física y matemáticas. Siempre que sea posible, incluye explicaciones detalladas, ejemplos numéricos y referencias a teorías o descubrimientos relevantes (por ejemplo, relatividad general, evolución estelar, espectroscopía, etc.). No simplifiques en exceso. Si la pregunta tiene múltiples dimensiones (como observacional y teórica), aborda todas. ¿Estás listo para empezar?\",\n",
|
||||||
" rol=\"asistente\",\n",
|
" rol=\"astronomo\",\n",
|
||||||
|
" max_iterations=5,\n",
|
||||||
" memoria=memoria,\n",
|
" memoria=memoria,\n",
|
||||||
" objetivos=[\"Asistir al usuario en tareas complejas\", \"usar herramientas para obtener información adicional\"]\n",
|
" objetivos=[\"Responder preguntas sobre astronomía y astrofísica\", \"Proporcionar explicaciones detalladas y ejemplos numéricos\"],\n",
|
||||||
" # tools=\n",
|
|
||||||
"\n",
|
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"respuesta = agente_con_herramientas.interactuar(\n",
|
"\n",
|
||||||
" prompt=\"Hola como estas?\",\n",
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"respuesta2 = await agente2.interactuar_en_bucle(\n",
|
||||||
|
" prompt=\"De donde venimos y donde vamos?\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(respuesta)"
|
"for r in respuesta2:\n",
|
||||||
|
" print(r)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 1,
|
||||||
"id": "5206b9c6",
|
"id": "5206b9c6",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": 2,
|
||||||
"id": "63a0b954",
|
"id": "63a0b954",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": 3,
|
||||||
"id": "0575f424",
|
"id": "0575f424",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -38,17 +38,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": 4,
|
||||||
"id": "a5266309",
|
"id": "a5266309",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text/plain": [
|
"text/plain": [
|
||||||
"1"
|
"'PGCR20250510-02f3cf9610127084237'"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 3,
|
"execution_count": 4,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"modelo_cred = repo_cred.get_by_id(1)\n",
|
"modelo_cred = repo_cred.get_by_id(\"PGCR20250510-02f3cf9610127084237\")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(modelo_cred.titulo)"
|
"print(modelo_cred.titulo)"
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"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": 2,
|
||||||
|
"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": 9,
|
||||||
|
"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: fdsfdsfsdfewww\n",
|
||||||
|
"[DEBUG] Nota creada: titulo='fdsfdsfsdfewww', 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-0cf0187e58905045667\n",
|
||||||
|
"[SUCCESS] Nota 'fdsfdsfsdfewww' agregada con éxito a la biblioteca 'biblio_Pruebas_1'.\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"{'mensaje': \"Nota 'fdsfdsfsdfewww' agregada con éxito a la biblioteca 'biblio_Pruebas_1'.\",\n",
|
||||||
|
" 'nota_id': 'NOTA20250511-0cf0187e58905045667'}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 9,
|
||||||
|
"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=\"fdsfdsfsdfewww\"\n",
|
||||||
|
")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 12,
|
||||||
|
"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": 13,
|
||||||
|
"id": "ae4f2994",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"[{'id': 'NOTA20250511-6cf9b177a2249549641',\n",
|
||||||
|
" 'titulo': 'Hola que tal',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-664831e1bd118315114',\n",
|
||||||
|
" 'titulo': 'Holoooo',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-04dbb203a9126228444',\n",
|
||||||
|
" 'titulo': 'sajdhasjdhasjdh',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-668f68e425271569668',\n",
|
||||||
|
" 'titulo': 'fsdfdf',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-a6ad7166d5660286632',\n",
|
||||||
|
" 'titulo': 'fsdfdf',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-639fa883c2266940759',\n",
|
||||||
|
" 'titulo': 'fsdfdf',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-27e86a8da6529002860',\n",
|
||||||
|
" 'titulo': 'fsdfdf',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-06479aca23973772356',\n",
|
||||||
|
" 'titulo': 'fsdfdf',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-0d577e3336174429305',\n",
|
||||||
|
" 'titulo': 'fdsfdsfsdfewww',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []},\n",
|
||||||
|
" {'id': 'NOTA20250511-0cf0187e58905045667',\n",
|
||||||
|
" 'titulo': 'fdsfdsfsdfewww',\n",
|
||||||
|
" 'tags': [],\n",
|
||||||
|
" 'texto': '',\n",
|
||||||
|
" 'resumen': '',\n",
|
||||||
|
" 'conexiones': []}]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 13,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "b02bfb00",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Your branch is up to date with 'origin/main'.\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Switched to branch 'main'\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"!git checkout main"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "92d482e6",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Updating 234639a..20173e9\n",
|
||||||
|
"Fast-forward\n",
|
||||||
|
" .gitignore | 11 +\n",
|
||||||
|
" Apikeys.ipynb | 128 +--\n",
|
||||||
|
" {llms/MCPs => backend}/__init__.py | 0\n",
|
||||||
|
" {llms/Modelos => backend/api}/__init__.py | 0\n",
|
||||||
|
" {llms => backend/api/v1}/__init__.py | 0\n",
|
||||||
|
" backend/api/v1/endpoints/ping.py | 9 +\n",
|
||||||
|
" backend/api/v1/router.py | 7 +\n",
|
||||||
|
" {security => backend/deps}/__init__.py | 0\n",
|
||||||
|
" backend/deps/auth.py | 0\n",
|
||||||
|
" backend/main.py | 24 +\n",
|
||||||
|
" data/files/txt/tree.txt | 980 +++++++++++++++++++++\n",
|
||||||
|
" entrypoint/init_db.py | 2 +-\n",
|
||||||
|
" frontend/.gitignore | 3 +\n",
|
||||||
|
" frontend/index.html | 4 +-\n",
|
||||||
|
" frontend/package-lock.json | 345 ++++++++\n",
|
||||||
|
" frontend/package.json | 2 +\n",
|
||||||
|
" frontend/src/assets/icons/favicon.svg | 55 ++\n",
|
||||||
|
" frontend/src/assets/icons/favicon.tsx | 37 +\n",
|
||||||
|
" frontend/src/assets/icons/index.ts | 18 +\n",
|
||||||
|
" .../components/{ => Appshell}/Appshell.module.css | 25 +-\n",
|
||||||
|
" .../src/components/{ => Appshell}/Appshell.tsx | 97 +-\n",
|
||||||
|
" frontend/src/components/HoloShader.tsx | 30 +-\n",
|
||||||
|
" frontend/src/components/Links/MainlLinks.tsx | 0\n",
|
||||||
|
" frontend/src/components/LlamadorAPI.tsx | 11 +-\n",
|
||||||
|
" frontend/src/components/MetodoSelect.tsx | 4 +-\n",
|
||||||
|
" frontend/src/components/Welcome/Welcome.tsx | 6 +-\n",
|
||||||
|
" frontend/src/components/botoncito.tsx | 16 -\n",
|
||||||
|
" frontend/src/data/navigationsLinks_1.ts | 20 +\n",
|
||||||
|
" frontend/src/data/submenuLinks_1.ts | 35 +\n",
|
||||||
|
" frontend/src/favicon.svg | 1 -\n",
|
||||||
|
" frontend/src/pages/404.tsx | 55 +-\n",
|
||||||
|
" frontend/src/pages/Analitica.tsx | 6 +-\n",
|
||||||
|
" frontend/src/pages/Consulta_api.tsx | 4 +-\n",
|
||||||
|
" frontend/src/pages/Home.page.tsx | 12 +-\n",
|
||||||
|
" frontend/src/pages/Plantilla.tsx | 2 +-\n",
|
||||||
|
" frontend/src/pages/Prueba_appshell.tsx | 7 +-\n",
|
||||||
|
" frontend/src/theme.ts | 57 +-\n",
|
||||||
|
" frontend/src/types/svg.d.ts | 7 +\n",
|
||||||
|
" frontend/src/types/vite-env.d.ts | 1 +\n",
|
||||||
|
" frontend/tsconfig.json | 2 +-\n",
|
||||||
|
" frontend/{vite.config.mjs => vite.config.js} | 5 +-\n",
|
||||||
|
" frontend/yarn.lock | 160 +++-\n",
|
||||||
|
" llms/Agente.py | 122 ---\n",
|
||||||
|
" llms/Modelos/Openai_model.py | 64 --\n",
|
||||||
|
" main.py | 25 +-\n",
|
||||||
|
" prueba_loop_agente.py | 94 +-\n",
|
||||||
|
" src/ApiKeys/openai_apikey_mmr.py | 2 +-\n",
|
||||||
|
" src/ConexionApis/OpenAi_conexion.py | 15 +-\n",
|
||||||
|
" src/Credenciales/postgres_credencial_mmr.py | 2 +-\n",
|
||||||
|
" src/Llms/Agente.py | 196 +++++\n",
|
||||||
|
" {llms => src/Llms}/MCPs/MCPStdioServer.py | 0\n",
|
||||||
|
" src/Llms/MCPs/__init__.py | 0\n",
|
||||||
|
" {llms => src/Llms}/Memory/Base_MemoryConv.py | 0\n",
|
||||||
|
" {llms => src/Llms}/Memory/postgres_MemoryConv.py | 2 +-\n",
|
||||||
|
" {llms => src/Llms}/Modelos/Base_model.py | 2 +-\n",
|
||||||
|
" src/Llms/Modelos/Openai_model.py | 82 ++\n",
|
||||||
|
" {llms => src/Llms}/Modelos/Openai_model_mmr.py | 2 +-\n",
|
||||||
|
" src/Llms/Modelos/__init__.py | 0\n",
|
||||||
|
" src/Llms/__init__.py | 0\n",
|
||||||
|
" {security => src/Security}/Encriptar.py | 0\n",
|
||||||
|
" src/Security/__init__.py | 0\n",
|
||||||
|
" 61 files changed, 2343 insertions(+), 453 deletions(-)\n",
|
||||||
|
" rename {llms/MCPs => backend}/__init__.py (100%)\n",
|
||||||
|
" rename {llms/Modelos => backend/api}/__init__.py (100%)\n",
|
||||||
|
" rename {llms => backend/api/v1}/__init__.py (100%)\n",
|
||||||
|
" create mode 100644 backend/api/v1/endpoints/ping.py\n",
|
||||||
|
" create mode 100644 backend/api/v1/router.py\n",
|
||||||
|
" rename {security => backend/deps}/__init__.py (100%)\n",
|
||||||
|
" create mode 100644 backend/deps/auth.py\n",
|
||||||
|
" create mode 100644 backend/main.py\n",
|
||||||
|
" create mode 100644 frontend/src/assets/icons/favicon.svg\n",
|
||||||
|
" create mode 100644 frontend/src/assets/icons/favicon.tsx\n",
|
||||||
|
" create mode 100644 frontend/src/assets/icons/index.ts\n",
|
||||||
|
" rename frontend/src/components/{ => Appshell}/Appshell.module.css (82%)\n",
|
||||||
|
" rename frontend/src/components/{ => Appshell}/Appshell.tsx (62%)\n",
|
||||||
|
" create mode 100644 frontend/src/components/Links/MainlLinks.tsx\n",
|
||||||
|
" delete mode 100644 frontend/src/components/botoncito.tsx\n",
|
||||||
|
" create mode 100644 frontend/src/data/navigationsLinks_1.ts\n",
|
||||||
|
" create mode 100644 frontend/src/data/submenuLinks_1.ts\n",
|
||||||
|
" delete mode 100644 frontend/src/favicon.svg\n",
|
||||||
|
" create mode 100644 frontend/src/types/svg.d.ts\n",
|
||||||
|
" create mode 100644 frontend/src/types/vite-env.d.ts\n",
|
||||||
|
" rename frontend/{vite.config.mjs => vite.config.js} (74%)\n",
|
||||||
|
" delete mode 100644 llms/Agente.py\n",
|
||||||
|
" delete mode 100644 llms/Modelos/Openai_model.py\n",
|
||||||
|
" create mode 100644 src/Llms/Agente.py\n",
|
||||||
|
" rename {llms => src/Llms}/MCPs/MCPStdioServer.py (100%)\n",
|
||||||
|
" create mode 100644 src/Llms/MCPs/__init__.py\n",
|
||||||
|
" rename {llms => src/Llms}/Memory/Base_MemoryConv.py (100%)\n",
|
||||||
|
" rename {llms => src/Llms}/Memory/postgres_MemoryConv.py (97%)\n",
|
||||||
|
" rename {llms => src/Llms}/Modelos/Base_model.py (95%)\n",
|
||||||
|
" create mode 100644 src/Llms/Modelos/Openai_model.py\n",
|
||||||
|
" rename {llms => src/Llms}/Modelos/Openai_model_mmr.py (97%)\n",
|
||||||
|
" create mode 100644 src/Llms/Modelos/__init__.py\n",
|
||||||
|
" create mode 100644 src/Llms/__init__.py\n",
|
||||||
|
" rename {security => src/Security}/Encriptar.py (100%)\n",
|
||||||
|
" create mode 100644 src/Security/__init__.py\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"!git merge cambios_frontend\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "91a704a5",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"remote: . Processing 1 references \n",
|
||||||
|
"remote: Processed 1 references in total \n",
|
||||||
|
"To http://10.8.0.6:3123/egutierrez/Fitz_Studio.git\n",
|
||||||
|
" 234639a..20173e9 main -> main\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"!git push origin main"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# client.py
|
||||||
|
import asyncio
|
||||||
|
from src.Llms.MCPs.Mcp_client import MCPClient
|
||||||
|
from src.Llms.MCPs.Http_mcp_server import HttpMCPServer
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
client = MCPClient()
|
||||||
|
|
||||||
|
client.register_server(HttpMCPServer(
|
||||||
|
name="tools",
|
||||||
|
path="IGNORED_IN_CLIENT", # no importa aquí
|
||||||
|
host="127.0.0.1",
|
||||||
|
port=4300,
|
||||||
|
path_http="/tools"
|
||||||
|
))
|
||||||
|
|
||||||
|
await client.connect_all()
|
||||||
|
|
||||||
|
result = await client.call_tool({
|
||||||
|
"server": "tools",
|
||||||
|
"tool": "get_hostname",
|
||||||
|
"input": {}
|
||||||
|
})
|
||||||
|
print("RESULT:", result)
|
||||||
|
|
||||||
|
await client.disconnect_all()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
+92
-28
@@ -4,18 +4,30 @@ from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo
|
|||||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||||
from entrypoint.init_db import db_credencial
|
from entrypoint.init_db import db_credencial
|
||||||
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||||
from llms.Modelos.Openai_model import ModeloOpenAI
|
from src.Llms.Modelos.Openai_model import ModeloOpenAI
|
||||||
from llms.Agente import AgenteAI
|
from src.Llms.Agente import AgenteAI
|
||||||
|
from src.Llms.Memory.postgres_MemoryConv import MemoryConvPostgres
|
||||||
|
from fastmcp.client.transports import StreamableHttpTransport
|
||||||
|
from fastmcp.client import Client
|
||||||
|
from src.Llms.MCPs.McpClient import MCPClient # ya tienes esta clase
|
||||||
|
from src.Llms.MCPs.McpClient_Registry import ClientRegistry # o ajusta según tu estructura
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
# 🔌 Conexión
|
|
||||||
|
# Usar Credencial openai
|
||||||
|
|
||||||
conexion_admin = PostgresConexion(db_credencial)
|
conexion_admin = PostgresConexion(db_credencial)
|
||||||
repo = OpenAICredencialRepo(conexion_admin)
|
repo = OpenAICredencialRepo(conexion_admin)
|
||||||
credencial_openai = repo.get_by_id(1)
|
credencial_openai = repo.get_by_id("OPAK20250513-61b29978b7604031014")
|
||||||
print(f"✅ Credencial: {credencial_openai.titulo}")
|
|
||||||
|
|
||||||
# 🤖 Modelo
|
|
||||||
cliente = OpenAICliente(credencial_openai)
|
cliente = OpenAICliente(credencial_openai)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# crea el modelo (openai)
|
||||||
|
|
||||||
modelo = ModeloOpenAI(
|
modelo = ModeloOpenAI(
|
||||||
cliente=cliente,
|
cliente=cliente,
|
||||||
model="gpt-4o",
|
model="gpt-4o",
|
||||||
@@ -23,31 +35,83 @@ async def main():
|
|||||||
top_p=1.0
|
top_p=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# 🧠 Agente
|
# Le otorga memoria
|
||||||
agente_con_herramientas = AgenteAI(
|
|
||||||
modelo=modelo,
|
memoria = MemoryConvPostgres(
|
||||||
nombre="Agente con herramientas",
|
credencial=db_credencial,
|
||||||
descripcion="Un agente que puede usar herramientas",
|
nombre_tabla="memoria_conversacion_pruebas",
|
||||||
system_prompt="Eres un asistente que puede usar herramientas para responder preguntas.",
|
k=10
|
||||||
rol="asistente",
|
|
||||||
objetivos=["Asistir al usuario en tareas complejas", "usar herramientas para obtener información adicional"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
print("\n🤖 Agente listo. Escribe 'salir' para terminar.")
|
|
||||||
|
|
||||||
# 🔁 Loop de interacción
|
# Cargamos las herramientas
|
||||||
while True:
|
|
||||||
entrada = input("🧑 Tú: ")
|
|
||||||
if entrada.strip().lower() in {"salir", "exit", "quit"}:
|
|
||||||
print("👋 Saliendo del agente...")
|
|
||||||
break
|
|
||||||
|
|
||||||
respuesta = await agente_con_herramientas.interactuar(prompt=entrada)
|
herramientas = MCPClient.from_http(
|
||||||
print(f"🤖 Agente: {respuesta}\n")
|
name="tools",
|
||||||
|
url="http://127.0.0.1:4300/tools/"
|
||||||
|
)
|
||||||
|
|
||||||
|
math = MCPClient.from_http(
|
||||||
|
name="math",
|
||||||
|
url="http://127.0.0.1:4200/math/"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Las añadimos al registro de herramientas
|
||||||
|
|
||||||
|
registry = ClientRegistry()
|
||||||
|
|
||||||
|
|
||||||
|
registry.add("tools", herramientas)
|
||||||
|
registry.add("math", math)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# --- INICIALIZACIÓN DEL AGENTE ---
|
||||||
|
agente2 = AgenteAI(
|
||||||
|
modelo=modelo,
|
||||||
|
nombre="Asistente Inteligente",
|
||||||
|
descripcion="Un asistente conversacional versátil, capaz de resolver problemas, acceder a herramientas y proporcionar respuestas útiles.",
|
||||||
|
system_prompt=(
|
||||||
|
"Eres un asistente inteligente que ayuda al usuario a resolver tareas, responder preguntas y usar herramientas disponibles si es necesario. "
|
||||||
|
"Debes razonar paso a paso, y si se detecta que una herramienta MCP es útil, actúa generando el bloque MCP apropiado sin dar más explicaciones. "
|
||||||
|
"Siempre estructura tus respuestas con claridad, y termina con <END> cuando creas haber completado la tarea."
|
||||||
|
),
|
||||||
|
rol="asistente",
|
||||||
|
objetivos=[
|
||||||
|
"Resolver tareas del usuario",
|
||||||
|
"Usar herramientas MCP si es útil",
|
||||||
|
"Responder de forma clara y útil"
|
||||||
|
],
|
||||||
|
|
||||||
|
# max_iterations=3,
|
||||||
|
# memoria=memoria,
|
||||||
|
|
||||||
|
mcp=registry # ← ✅ Integración del cliente MCP
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --- FUNCIÓN DE EJECUCIÓN ---
|
||||||
|
async def probar_interaccion_stream():
|
||||||
|
# # 🔌 Conectar a los servidores MCP registrados
|
||||||
|
# await mcp_client.connect_all()
|
||||||
|
|
||||||
|
print("Respuesta en streaming:\n")
|
||||||
|
respuesta_gen = await agente2.interactuar_en_bucle(
|
||||||
|
"¿Cuál es mi nombre de usuario en este sistema?",
|
||||||
|
stream=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async for token in respuesta_gen:
|
||||||
|
print(token, end="", flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
await probar_interaccion_stream()
|
||||||
|
|
||||||
|
|
||||||
|
# Ejecutar
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import os
|
|
||||||
if os.name == "nt":
|
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+19
-64
@@ -1,74 +1,29 @@
|
|||||||
import asyncio
|
|
||||||
from llms.MCPs.MCPStdioServer import MCPStdioServer
|
|
||||||
import os
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
prueba = MCPStdioServer(
|
|
||||||
name="prueba_server_mcp",
|
|
||||||
command="C:/Users/lucas/Desktop/mcps/.venv/Scripts/python.exe",
|
|
||||||
args=["C:/Users/lucas/Desktop/mcps/server_mcp_python/server_mcp.py"],
|
|
||||||
)
|
|
||||||
await prueba.start()
|
|
||||||
print("Herramientas:", prueba.get_tool_names())
|
|
||||||
|
|
||||||
await prueba.stop() # <- esto previene el error
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Asegura compatibilidad para subprocess en Windows
|
|
||||||
if os.name == "nt":
|
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
asyncio.run(main())
|
async def test_registry(registry: ClientRegistry):
|
||||||
|
tools = await registry.listar_tools_por_cliente()
|
||||||
|
prompts = await registry.listar_prompts_por_cliente()
|
||||||
|
resources = await registry.listar_resources_por_cliente()
|
||||||
|
|
||||||
|
print("\n🔧 Herramientas:", tools)
|
||||||
|
|
||||||
|
|
||||||
|
print("\n📋 Prompts:", prompts)
|
||||||
|
|
||||||
|
print("\n📂 Resources:", resources)
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(test_registry(registry))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def test_wrapper():
|
||||||
|
|
||||||
from src.ApiKeys.openai_apikey import OpenAICredencial
|
# 2. Llamar a una herramienta de prueba
|
||||||
from src.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo
|
result = await herramientas.call_tool("generate_uuid")
|
||||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
print("\n🆔 UUID generado:", result[0].text) # Accedemos al contenido directamente
|
||||||
|
|
||||||
# 1. Crear instancia de conexión (asegúrate de configurar bien tu conexión en Base_conexion)
|
|
||||||
from entrypoint.init_db import db_credencial
|
|
||||||
conexion_admin = PostgresConexion(db_credencial)
|
|
||||||
|
|
||||||
# 3. Guardar la credencial en la base de datos
|
|
||||||
repo = OpenAICredencialRepo(conexion_admin)
|
|
||||||
credencial_openai = repo.get_by_id(1)
|
|
||||||
print(f"✅ Credencial: {credencial_openai.titulo}")
|
|
||||||
|
|
||||||
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
|
||||||
|
|
||||||
cliente = OpenAICliente(credencial_openai)
|
|
||||||
|
|
||||||
from llms.Modelos.Openai_model import ModeloOpenAI
|
|
||||||
|
|
||||||
modelo = ModeloOpenAI(
|
|
||||||
cliente=cliente,
|
|
||||||
model="gpt-4o",
|
|
||||||
temperature=1,
|
|
||||||
top_p=1.0
|
|
||||||
)
|
|
||||||
|
|
||||||
from llms.Agente import AgenteAI
|
|
||||||
|
|
||||||
|
|
||||||
agente_con_herramientas = AgenteAI(
|
# asyncio.run(test_wrapper())
|
||||||
modelo=modelo,
|
|
||||||
nombre="Agente con herramientas",
|
|
||||||
descripcion="Un agente que puede usar herramientas",
|
|
||||||
system_prompt="Eres un asistente que puede usar herramientas para responder preguntas.",
|
|
||||||
rol="asistente",
|
|
||||||
objetivos=["Asistir al usuario en tareas complejas", "usar herramientas para obtener información adicional"]
|
|
||||||
# tools=
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
respuesta = agente_con_herramientas.interactuar(
|
|
||||||
prompt="Hola como estas?",
|
|
||||||
)
|
|
||||||
|
|
||||||
print(respuesta)
|
|
||||||
@@ -28,3 +28,4 @@ def save_tree_to_file(start_path='.', max_depth=2, output_file='tree.txt'):
|
|||||||
# Ejemplo de uso:
|
# Ejemplo de uso:
|
||||||
# Puedes cambiar estos valores según lo necesites
|
# Puedes cambiar estos valores según lo necesites
|
||||||
save_tree_to_file(start_path=r'E:\Fitz_Studio', max_depth=3, output_file=r'E:\Fitz_Studio\data\files\txt\tree.txt')
|
save_tree_to_file(start_path=r'E:\Fitz_Studio', max_depth=3, output_file=r'E:\Fitz_Studio\data\files\txt\tree.txt')
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||||
|
|
||||||
class OpenAICredencial:
|
class OpenAICredencial:
|
||||||
def __init__(self, titulo: str, api_key: str, organizacion: str = None):
|
def __init__(self, titulo: str, api_key: str, organizacion: str = None, id: str = None):
|
||||||
"""
|
"""
|
||||||
:param titulo: Nombre descriptivo para esta credencial.
|
:param titulo: Nombre descriptivo para esta credencial.
|
||||||
:param api_key: Clave secreta de la API de OpenAI.
|
:param api_key: Clave secreta de la API de OpenAI.
|
||||||
:param organizacion: (Opcional) ID de la organización asociada a la cuenta de OpenAI.
|
:param organizacion: (Opcional) ID de la organización asociada a la cuenta de OpenAI.
|
||||||
"""
|
"""
|
||||||
|
self.id = id if id is not None else GeneradorIDUnico("OPAK").generar()
|
||||||
self.titulo = titulo
|
self.titulo = titulo
|
||||||
self.api_key = api_key
|
self.api_key = api_key
|
||||||
self.organizacion = organizacion
|
self.organizacion = organizacion
|
||||||
|
|||||||
@@ -6,8 +6,15 @@ from sqlalchemy import Column, Integer, String
|
|||||||
from src.ConexionSql.Base_conexion import ConexionBase
|
from src.ConexionSql.Base_conexion import ConexionBase
|
||||||
from src.base import Base
|
from src.base import Base
|
||||||
from src.ApiKeys.openai_apikey import OpenAICredencial
|
from src.ApiKeys.openai_apikey import OpenAICredencial
|
||||||
from security.Encriptar import Encriptar_fernet
|
from src.Security.Encriptar import Encriptar_fernet
|
||||||
from entrypoint import ENV_PATH
|
from entrypoint import ENV_PATH
|
||||||
|
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||||
|
|
||||||
|
|
||||||
|
from sqlalchemy import Column, String
|
||||||
|
from src.ArquitectureLayer.Model import Model_base
|
||||||
|
from src.ArquitectureLayer.Repo import Repo_base
|
||||||
|
|
||||||
|
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# Cargar clave maestra
|
# Cargar clave maestra
|
||||||
@@ -21,10 +28,10 @@ if pssword is None:
|
|||||||
# MODELO (SQLAlchemy)
|
# MODELO (SQLAlchemy)
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class OpenAICredencialModel(Base):
|
class OpenAICredencialModel(Base, Model_base):
|
||||||
__tablename__ = 'openai_credenciales'
|
__tablename__ = 'openai_credenciales'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(String, primary_key=True)
|
||||||
titulo = Column(String, nullable=False)
|
titulo = Column(String, nullable=False)
|
||||||
api_key = Column(String, nullable=False) # Encriptada como base64 string
|
api_key = Column(String, nullable=False) # Encriptada como base64 string
|
||||||
organizacion = Column(String, nullable=True)
|
organizacion = Column(String, nullable=True)
|
||||||
@@ -33,30 +40,23 @@ class OpenAICredencialModel(Base):
|
|||||||
# MAPPER
|
# MAPPER
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class OpenAICredencialMapper:
|
class OpenAICredencialMapper(Mapper_base[OpenAICredencial, OpenAICredencialModel]):
|
||||||
@staticmethod
|
|
||||||
def to_dict(obj: OpenAICredencial) -> dict:
|
|
||||||
return {
|
|
||||||
"titulo": obj.titulo,
|
|
||||||
"api_key": base64.b64encode(
|
|
||||||
Encriptar_fernet.encriptar(obj.api_key, pssword)
|
|
||||||
).decode('utf-8'),
|
|
||||||
"organizacion": obj.organizacion
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(data: dict) -> OpenAICredencial:
|
def to_model(obj: OpenAICredencial) -> OpenAICredencialModel:
|
||||||
return OpenAICredencial(
|
return OpenAICredencialModel(
|
||||||
titulo=data["titulo"],
|
id=obj.id,
|
||||||
api_key=Encriptar_fernet.desencriptar(
|
titulo=obj.titulo,
|
||||||
base64.b64decode(data["api_key"]), pssword
|
api_key=base64.b64encode(
|
||||||
),
|
Encriptar_fernet.encriptar(obj.api_key, pssword)
|
||||||
organizacion=data.get("organizacion")
|
).decode("utf-8"),
|
||||||
|
organizacion=obj.organizacion
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_model(model: OpenAICredencialModel) -> OpenAICredencial:
|
def from_model(model: OpenAICredencialModel) -> OpenAICredencial:
|
||||||
return OpenAICredencial(
|
return OpenAICredencial(
|
||||||
|
id=model.id,
|
||||||
titulo=model.titulo,
|
titulo=model.titulo,
|
||||||
api_key=Encriptar_fernet.desencriptar(
|
api_key=Encriptar_fernet.desencriptar(
|
||||||
base64.b64decode(model.api_key), pssword
|
base64.b64decode(model.api_key), pssword
|
||||||
@@ -64,29 +64,44 @@ class OpenAICredencialMapper:
|
|||||||
organizacion=model.organizacion
|
organizacion=model.organizacion
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_dict(obj: OpenAICredencial) -> dict:
|
||||||
|
return {
|
||||||
|
"id": obj.id,
|
||||||
|
"titulo": obj.titulo,
|
||||||
|
"api_key": base64.b64encode(
|
||||||
|
Encriptar_fernet.encriptar(obj.api_key, pssword)
|
||||||
|
).decode("utf-8"),
|
||||||
|
"organizacion": obj.organizacion
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data: dict) -> OpenAICredencial:
|
||||||
|
return OpenAICredencial(
|
||||||
|
id=data["id"],
|
||||||
|
titulo=data["titulo"],
|
||||||
|
api_key=Encriptar_fernet.desencriptar(
|
||||||
|
base64.b64decode(data["api_key"]), pssword
|
||||||
|
),
|
||||||
|
organizacion=data.get("organizacion")
|
||||||
|
)
|
||||||
|
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# REPO
|
# REPO
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class OpenAICredencialRepo:
|
class OpenAICredencialRepo(Repo_base[OpenAICredencialModel, OpenAICredencial]):
|
||||||
def __init__(self, conexion: ConexionBase):
|
def __init__(self, conexion: ConexionBase):
|
||||||
self.session = conexion.get_session()
|
super().__init__(
|
||||||
|
session=conexion.get_session(),
|
||||||
def add(self, credencial: OpenAICredencial) -> int:
|
modelo=OpenAICredencialModel,
|
||||||
data = OpenAICredencialMapper.to_dict(credencial)
|
mapper=OpenAICredencialMapper
|
||||||
model = OpenAICredencialModel(**data)
|
)
|
||||||
self.session.add(model)
|
|
||||||
self.session.commit()
|
|
||||||
return model.id
|
|
||||||
|
|
||||||
def get_all(self) -> list[OpenAICredencial]:
|
|
||||||
models = self.session.query(OpenAICredencialModel).all()
|
|
||||||
return [OpenAICredencialMapper.from_model(m) for m in models]
|
|
||||||
|
|
||||||
def get_by_titulo(self, titulo: str) -> OpenAICredencial | None:
|
def get_by_titulo(self, titulo: str) -> OpenAICredencial | None:
|
||||||
model = self.session.query(OpenAICredencialModel).filter_by(titulo=titulo).first()
|
model = (
|
||||||
return OpenAICredencialMapper.from_model(model) if model else None
|
self.session.query(self.Modelo)
|
||||||
|
.filter_by(titulo=titulo, sys_deleted_at=None)
|
||||||
def get_by_id(self, id_: int) -> OpenAICredencial | None:
|
.first()
|
||||||
model = self.session.get(OpenAICredencialModel, id_)
|
)
|
||||||
return OpenAICredencialMapper.from_model(model) if model else None
|
return self.Mapper.from_model(model) if model else None
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# src\ArquitectureLayer\Mapper.py
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import TypeVar, Generic, Type
|
||||||
|
import json
|
||||||
|
|
||||||
|
TDominio = TypeVar("TDominio")
|
||||||
|
TModelo = TypeVar("TModelo")
|
||||||
|
|
||||||
|
class Mapper_base(ABC, Generic[TDominio, TModelo]):
|
||||||
|
# ----------------------------
|
||||||
|
# Conversiones individuales
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def to_model(obj: TDominio) -> TModelo:
|
||||||
|
"""Convierte objeto de dominio a modelo ORM"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def from_model(model: TModelo) -> TDominio:
|
||||||
|
"""Convierte modelo ORM a objeto de dominio"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def to_dict(obj: TDominio) -> dict:
|
||||||
|
"""Convierte objeto de dominio a diccionario plano"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abstractmethod
|
||||||
|
def from_dict(d: dict) -> TDominio:
|
||||||
|
"""Convierte diccionario plano a objeto de dominio"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def to_json(cls, obj: TDominio) -> str:
|
||||||
|
"""Convierte objeto de dominio a JSON string"""
|
||||||
|
return json.dumps(cls.to_dict(obj), default=str)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json_str: str) -> TDominio:
|
||||||
|
"""Convierte JSON string a objeto de dominio"""
|
||||||
|
return cls.from_dict(json.loads(json_str))
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Conversiones en lote (bulk)
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def to_model_list(cls, objs: list[TDominio]) -> list[TModelo]:
|
||||||
|
return [cls.to_model(o) for o in objs]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_model_list(cls, models: list[TModelo]) -> list[TDominio]:
|
||||||
|
return [cls.from_model(m) for m in models]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def to_dict_list(cls, objs: list[TDominio]) -> list[dict]:
|
||||||
|
return [cls.to_dict(o) for o in objs]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict_list(cls, dicts: list[dict]) -> list[TDominio]:
|
||||||
|
return [cls.from_dict(d) for d in dicts]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def to_json_list(cls, objs: list[TDominio]) -> str:
|
||||||
|
return json.dumps(cls.to_dict_list(objs), default=str)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json_list(cls, json_str: str) -> list[TDominio]:
|
||||||
|
return cls.from_dict_list(json.loads(json_str))
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# src\ArquitectureLayer\Model.py
|
||||||
|
|
||||||
|
from sqlalchemy import Column, DateTime, String, Integer, Text, func
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr, as_declarative
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
@as_declarative()
|
||||||
|
class Model_base:
|
||||||
|
__abstract__ = True
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_created_at(cls):
|
||||||
|
return Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_created_by(cls):
|
||||||
|
return Column(String, nullable=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_updated_at(cls):
|
||||||
|
return Column(DateTime(timezone=True), onupdate=func.now(), nullable=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_updated_by(cls):
|
||||||
|
return Column(String, nullable=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_version(cls):
|
||||||
|
return Column(Integer, default=1, nullable=False)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_notes(cls):
|
||||||
|
return Column(Text, nullable=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def sys_deleted_at(cls):
|
||||||
|
return Column(DateTime(timezone=True), nullable=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
id_val = getattr(self, "id", None)
|
||||||
|
return f"<{self.__class__.__name__} id={id_val}>"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
cls = self.__class__.__name__
|
||||||
|
id_val = getattr(self, "id", None)
|
||||||
|
return f"{cls}(id={id_val})"
|
||||||
|
|
||||||
|
def __json__(self) -> dict:
|
||||||
|
"""Devuelve una representación JSON serializable (dict plano)."""
|
||||||
|
out = {}
|
||||||
|
|
||||||
|
# Prevención de error: solo ejecuta si __table__ existe
|
||||||
|
if not hasattr(self, "__table__"):
|
||||||
|
return out
|
||||||
|
|
||||||
|
for attr in self.__table__.columns:
|
||||||
|
val = getattr(self, attr.name, None)
|
||||||
|
if isinstance(val, datetime):
|
||||||
|
out[attr.name] = val.isoformat()
|
||||||
|
else:
|
||||||
|
out[attr.name] = val
|
||||||
|
|
||||||
|
return out
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# src\ArquitectureLayer\Repo.py
|
||||||
|
|
||||||
|
from abc import ABC
|
||||||
|
from typing import Type, TypeVar, Generic, Optional
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy import func
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from src.ArquitectureLayer.Mapper import Mapper_base # Asegúrate de importar tu ABC base
|
||||||
|
|
||||||
|
TModelo = TypeVar("TModelo")
|
||||||
|
TDominio = TypeVar("TDominio")
|
||||||
|
|
||||||
|
class Repo_base(ABC, Generic[TModelo, TDominio]):
|
||||||
|
def __init__(self, session: Session, modelo: type[TModelo], mapper: type[Mapper_base[TDominio, TModelo]]):
|
||||||
|
self.session = session
|
||||||
|
self.Modelo = modelo
|
||||||
|
self.Mapper = mapper
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# ADD
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def add(self, dominio: TDominio, created_by: Optional[str] = None, notes: Optional[str] = None) -> str:
|
||||||
|
data = self.Mapper.to_dict(dominio)
|
||||||
|
data.update({
|
||||||
|
"sys_created_by": created_by,
|
||||||
|
"sys_notes": notes,
|
||||||
|
"sys_version": 1
|
||||||
|
})
|
||||||
|
model = self.Modelo(**data)
|
||||||
|
self.session.add(model)
|
||||||
|
self.session.commit()
|
||||||
|
return model.id
|
||||||
|
|
||||||
|
def add_many(self, dominios: list[TDominio], created_by: Optional[str] = None, notes: Optional[str] = None) -> list[str]:
|
||||||
|
ids = []
|
||||||
|
for dominio in dominios:
|
||||||
|
data = self.Mapper.to_dict(dominio)
|
||||||
|
data.update({
|
||||||
|
"sys_created_by": created_by,
|
||||||
|
"sys_notes": notes,
|
||||||
|
"sys_version": 1
|
||||||
|
})
|
||||||
|
model = self.Modelo(**data)
|
||||||
|
self.session.add(model)
|
||||||
|
ids.append(model.id)
|
||||||
|
self.session.commit()
|
||||||
|
return ids
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# GET
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def get_by_id(self, id_: str) -> Optional[TDominio]:
|
||||||
|
model = self.session.query(self.Modelo).filter_by(id=id_, sys_deleted_at=None).first()
|
||||||
|
return self.Mapper.from_model(model) if model else None
|
||||||
|
|
||||||
|
def get_all(self) -> list[TDominio]:
|
||||||
|
models = self.session.query(self.Modelo).filter_by(sys_deleted_at=None).all()
|
||||||
|
return self.Mapper.from_model_list(models)
|
||||||
|
|
||||||
|
def get_paginated(self, offset: int = 0, limit: int = 10) -> list[TDominio]:
|
||||||
|
models = self.session.query(self.Modelo).filter_by(sys_deleted_at=None).offset(offset).limit(limit).all()
|
||||||
|
return self.Mapper.from_model_list(models)
|
||||||
|
|
||||||
|
def get_deleted(self) -> list[TDominio]:
|
||||||
|
models = self.session.query(self.Modelo).filter(self.Modelo.sys_deleted_at.isnot(None)).all()
|
||||||
|
return self.Mapper.from_model_list(models)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# UPDATE
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def update(self, id_: str, new_data: dict, updated_by: Optional[str] = None, notes: Optional[str] = None) -> bool:
|
||||||
|
model = self.session.query(self.Modelo).filter_by(id=id_, sys_deleted_at=None).first()
|
||||||
|
if not model:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for key, value in new_data.items():
|
||||||
|
if hasattr(model, key):
|
||||||
|
setattr(model, key, value)
|
||||||
|
|
||||||
|
model.sys_updated_by = updated_by
|
||||||
|
model.sys_notes = notes
|
||||||
|
model.sys_version = (model.sys_version or 1) + 1
|
||||||
|
self.session.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def bulk_update(self, updates: list[tuple[str, dict]], updated_by: Optional[str] = None, notes: Optional[str] = None) -> int:
|
||||||
|
count = 0
|
||||||
|
for id_, data in updates:
|
||||||
|
if self.update(id_, data, updated_by=updated_by, notes=notes):
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# DELETE
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def delete_by_id(self, id_: str) -> bool:
|
||||||
|
model = self.session.query(self.Modelo).filter_by(id=id_).first()
|
||||||
|
if model:
|
||||||
|
self.session.delete(model)
|
||||||
|
self.session.commit()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_all(self) -> int:
|
||||||
|
deleted = self.session.query(self.Modelo).delete()
|
||||||
|
self.session.commit()
|
||||||
|
return deleted
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# SOFT DELETE
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def soft_delete(self, id_: str, deleted_by: Optional[str] = None, notes: Optional[str] = None) -> bool:
|
||||||
|
model = self.session.query(self.Modelo).filter_by(id=id_, sys_deleted_at=None).first()
|
||||||
|
if model:
|
||||||
|
model.sys_deleted_at = datetime.now()
|
||||||
|
model.sys_updated_by = deleted_by
|
||||||
|
model.sys_notes = notes
|
||||||
|
model.sys_version = (model.sys_version or 1) + 1
|
||||||
|
self.session.commit()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def soft_restore(self, id_: str, restored_by: Optional[str] = None, notes: Optional[str] = None) -> bool:
|
||||||
|
model = self.session.query(self.Modelo).filter_by(id=id_).first()
|
||||||
|
if model and model.sys_deleted_at is not None:
|
||||||
|
model.sys_deleted_at = None
|
||||||
|
model.sys_updated_by = restored_by
|
||||||
|
model.sys_notes = notes
|
||||||
|
model.sys_version = (model.sys_version or 1) + 1
|
||||||
|
self.session.commit()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# OTROS
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
def exists(self, id_: str) -> bool:
|
||||||
|
return self.session.query(self.Modelo).filter_by(id=id_, sys_deleted_at=None).first() is not None
|
||||||
|
|
||||||
|
def count(self) -> int:
|
||||||
|
return self.session.query(self.Modelo).filter_by(sys_deleted_at=None).count()
|
||||||
@@ -12,8 +12,19 @@ class OpenAICliente:
|
|||||||
self.client.organization = self.credencial.organizacion
|
self.client.organization = self.credencial.organizacion
|
||||||
|
|
||||||
# --- Chat Completions ---
|
# --- Chat Completions ---
|
||||||
def chat_completion(self, model: str, messages: list, **kwargs):
|
def chat_completion(self, model: str, messages: list, stream: bool = False, **kwargs):
|
||||||
return self.client.chat.completions.create(model=model, messages=messages, **kwargs)
|
response = self.client.chat.completions.create(
|
||||||
|
model=model,
|
||||||
|
messages=messages,
|
||||||
|
stream=stream, # Parámetro explícito
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
return self._handle_stream(response, stream) if stream else response
|
||||||
|
|
||||||
|
def _handle_stream(self, stream, _):
|
||||||
|
for chunk in stream:
|
||||||
|
if chunk.choices and chunk.choices[0].delta.content:
|
||||||
|
yield chunk.choices[0].delta.content
|
||||||
|
|
||||||
# --- Text Completions (legacy) ---
|
# --- Text Completions (legacy) ---
|
||||||
def completion(self, model: str, prompt: str, **kwargs):
|
def completion(self, model: str, prompt: str, **kwargs):
|
||||||
|
|||||||
@@ -1,7 +1,39 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from sqlalchemy.orm import Session
|
from datetime import datetime, timezone
|
||||||
|
from sqlalchemy.orm import Session, sessionmaker
|
||||||
|
from sqlalchemy.engine import Engine
|
||||||
|
from sqlalchemy import create_engine, text
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
||||||
class ConexionBase(ABC):
|
class ConexionBase(ABC):
|
||||||
|
def __init__(self, uri: str):
|
||||||
|
self.estado = "pendiente"
|
||||||
|
self.timestamp = datetime.now(timezone.utc)
|
||||||
|
self._engine: Engine = create_engine(uri)
|
||||||
|
self._Session = sessionmaker(bind=self._engine)
|
||||||
|
self._session_instance: Session | None = None
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_session(self) -> Session:
|
def get_session(self) -> Session:
|
||||||
pass
|
if self._session_instance is None:
|
||||||
|
self._session_instance = self._Session()
|
||||||
|
return self._session_instance
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_engine(self) -> Engine:
|
||||||
|
return self._engine
|
||||||
|
|
||||||
|
def probar_conexion(self) -> bool:
|
||||||
|
try:
|
||||||
|
with self._engine.connect() as connection:
|
||||||
|
connection.execute(text("SELECT 1"))
|
||||||
|
self.estado = "exito"
|
||||||
|
return True
|
||||||
|
except SQLAlchemyError:
|
||||||
|
self.estado = "fallo"
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self._session_instance is not None:
|
||||||
|
self._session_instance.close()
|
||||||
|
self._session_instance = None
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import create_engine, text
|
from sqlalchemy import create_engine, text
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker, Session
|
||||||
|
from sqlalchemy.engine import Engine
|
||||||
|
|
||||||
from src.ConexionSql.Base_conexion import ConexionBase
|
from src.ConexionSql.Base_conexion import ConexionBase
|
||||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||||
|
|
||||||
|
|
||||||
class PostgresConexion(ConexionBase):
|
class PostgresConexion(ConexionBase):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.estado = "pendiente"
|
self.estado = "pendiente"
|
||||||
@@ -18,28 +18,41 @@ class PostgresConexion(ConexionBase):
|
|||||||
self.port = credencial.port
|
self.port = credencial.port
|
||||||
self.dbname = credencial.dbname
|
self.dbname = credencial.dbname
|
||||||
self.user = credencial.user
|
self.user = credencial.user
|
||||||
self.password = credencial.password # se guarda la contraseña
|
self.password = credencial.password
|
||||||
uri = credencial.get_uri()
|
uri = credencial.get_uri()
|
||||||
else:
|
else:
|
||||||
self.user = kwargs.get("user")
|
self.user = kwargs.get("user")
|
||||||
self.password = kwargs.get("password") # se guarda la contraseña
|
self.password = kwargs.get("password")
|
||||||
self.host = kwargs.get("host")
|
self.host = kwargs.get("host")
|
||||||
self.port = kwargs.get("port", 5432)
|
self.port = kwargs.get("port", 5432)
|
||||||
self.dbname = kwargs.get("db") or kwargs.get("dbname")
|
self.dbname = kwargs.get("db") or kwargs.get("dbname")
|
||||||
uri = f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.dbname}"
|
uri = f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.dbname}"
|
||||||
|
|
||||||
self.engine = create_engine(uri)
|
self._engine: Engine = create_engine(uri)
|
||||||
self.SessionLocal = sessionmaker(bind=self.engine)
|
self._Session = sessionmaker(bind=self._engine)
|
||||||
|
|
||||||
def get_session(self):
|
# ✅ INICIALIZAR LA SESIÓN AQUÍ
|
||||||
return self.SessionLocal()
|
self._session_instance: Session | None = None
|
||||||
|
|
||||||
|
def get_session(self) -> Session:
|
||||||
|
if self._session_instance is None:
|
||||||
|
self._session_instance = self._Session()
|
||||||
|
return self._session_instance
|
||||||
|
|
||||||
|
def get_engine(self) -> Engine:
|
||||||
|
return self._engine
|
||||||
|
|
||||||
def probar_conexion(self) -> bool:
|
def probar_conexion(self) -> bool:
|
||||||
try:
|
try:
|
||||||
with self.engine.connect() as connection:
|
with self._engine.connect() as connection:
|
||||||
connection.execute(text("SELECT 1"))
|
connection.execute(text("SELECT 1"))
|
||||||
self.estado = "exito"
|
self.estado = "exito"
|
||||||
return True
|
return True
|
||||||
except SQLAlchemyError:
|
except SQLAlchemyError:
|
||||||
self.estado = "fallo"
|
self.estado = "fallo"
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self._session_instance is not None:
|
||||||
|
self._session_instance.close()
|
||||||
|
self._session_instance = None
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||||
|
|
||||||
class PostgresCredencial:
|
class PostgresCredencial:
|
||||||
def __init__(self, titulo: str, host: str, port: int, dbname: str, user: str, password: str):
|
def __init__(self, titulo: str, host: str, port: int, dbname: str, user: str, password: str, id: str = None):
|
||||||
|
self.id = id if id is not None else GeneradorIDUnico("PGCR").generar()
|
||||||
self.titulo = titulo
|
self.titulo = titulo
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
@@ -7,6 +10,7 @@ class PostgresCredencial:
|
|||||||
self.user = user
|
self.user = user
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
|
|
||||||
def get_uri(self) -> str:
|
def get_uri(self) -> str:
|
||||||
"""
|
"""
|
||||||
Retorna una URI de conexión para PostgreSQL.
|
Retorna una URI de conexión para PostgreSQL.
|
||||||
|
|||||||
@@ -2,11 +2,18 @@ import os
|
|||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from sqlalchemy import Column, Integer, String
|
from sqlalchemy import Column, Integer, String
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy import DateTime, Text, func
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
|
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||||
|
from src.ArquitectureLayer.Model import Model_base
|
||||||
|
from src.ArquitectureLayer.Repo import Repo_base
|
||||||
|
|
||||||
from src.ConexionSql.Base_conexion import ConexionBase
|
from src.ConexionSql.Base_conexion import ConexionBase
|
||||||
from src.base import Base
|
from src.base import Base
|
||||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||||
from security.Encriptar import Encriptar_fernet
|
from src.Security.Encriptar import Encriptar_fernet
|
||||||
|
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# Cargar clave maestra
|
# Cargar clave maestra
|
||||||
@@ -21,10 +28,10 @@ if pssword is None:
|
|||||||
# MODELO (SQLAlchemy)
|
# MODELO (SQLAlchemy)
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class PostgresCredencialModel(Base):
|
class PostgresCredencialModel(Base, Model_base):
|
||||||
__tablename__ = 'postgres_credenciales'
|
__tablename__ = 'postgres_credenciales'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(String, primary_key=True)
|
||||||
titulo = Column(String, nullable=False)
|
titulo = Column(String, nullable=False)
|
||||||
host = Column(String, nullable=False)
|
host = Column(String, nullable=False)
|
||||||
port = Column(Integer, nullable=False)
|
port = Column(Integer, nullable=False)
|
||||||
@@ -36,12 +43,40 @@ class PostgresCredencialModel(Base):
|
|||||||
# MAPPER
|
# MAPPER
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
import base64
|
class PostgresCredencialMapper(Mapper_base[PostgresCredencial, PostgresCredencialModel]):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_model(obj: PostgresCredencial) -> PostgresCredencialModel:
|
||||||
|
return PostgresCredencialModel(
|
||||||
|
id=obj.id,
|
||||||
|
titulo=obj.titulo,
|
||||||
|
host=obj.host,
|
||||||
|
port=obj.port,
|
||||||
|
dbname=obj.dbname,
|
||||||
|
user=obj.user,
|
||||||
|
password=base64.b64encode(
|
||||||
|
Encriptar_fernet.encriptar(obj.password, pssword)
|
||||||
|
).decode('utf-8')
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_model(model: PostgresCredencialModel) -> PostgresCredencial:
|
||||||
|
return PostgresCredencial(
|
||||||
|
id=model.id,
|
||||||
|
titulo=model.titulo,
|
||||||
|
host=model.host,
|
||||||
|
port=model.port,
|
||||||
|
dbname=model.dbname,
|
||||||
|
user=model.user,
|
||||||
|
password=Encriptar_fernet.desencriptar(
|
||||||
|
base64.b64decode(model.password), pssword
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
class PostgresCredencialMapper:
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_dict(obj: PostgresCredencial) -> dict:
|
def to_dict(obj: PostgresCredencial) -> dict:
|
||||||
return {
|
return {
|
||||||
|
"id": obj.id,
|
||||||
"titulo": obj.titulo,
|
"titulo": obj.titulo,
|
||||||
"host": obj.host,
|
"host": obj.host,
|
||||||
"port": obj.port,
|
"port": obj.port,
|
||||||
@@ -55,6 +90,7 @@ class PostgresCredencialMapper:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(data: dict) -> PostgresCredencial:
|
def from_dict(data: dict) -> PostgresCredencial:
|
||||||
return PostgresCredencial(
|
return PostgresCredencial(
|
||||||
|
id=data["id"],
|
||||||
titulo=data["titulo"],
|
titulo=data["titulo"],
|
||||||
host=data["host"],
|
host=data["host"],
|
||||||
port=data["port"],
|
port=data["port"],
|
||||||
@@ -65,42 +101,22 @@ class PostgresCredencialMapper:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_model(model: PostgresCredencialModel) -> PostgresCredencial:
|
|
||||||
return PostgresCredencial(
|
|
||||||
titulo=model.titulo,
|
|
||||||
host=model.host,
|
|
||||||
port=model.port,
|
|
||||||
dbname=model.dbname,
|
|
||||||
user=model.user,
|
|
||||||
password=Encriptar_fernet.desencriptar(
|
|
||||||
base64.b64decode(model.password), pssword
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# ----------------------
|
# ----------------------
|
||||||
# REPO
|
# REPO
|
||||||
# ----------------------
|
# ----------------------
|
||||||
|
|
||||||
class PostgresCredencialRepo:
|
class PostgresCredencialRepo(Repo_base[PostgresCredencialModel, PostgresCredencial]):
|
||||||
def __init__(self, conexion: ConexionBase):
|
def __init__(self, conexion: ConexionBase):
|
||||||
self.session = conexion.get_session()
|
super().__init__(
|
||||||
|
session=conexion.get_session(),
|
||||||
def add(self, credencial: PostgresCredencial) -> int:
|
modelo=PostgresCredencialModel,
|
||||||
data = PostgresCredencialMapper.to_dict(credencial)
|
mapper=PostgresCredencialMapper
|
||||||
model = PostgresCredencialModel(**data)
|
)
|
||||||
self.session.add(model)
|
|
||||||
self.session.commit()
|
|
||||||
return model.id
|
|
||||||
|
|
||||||
def get_all(self) -> list[PostgresCredencial]:
|
|
||||||
models = self.session.query(PostgresCredencialModel).all()
|
|
||||||
return [PostgresCredencialMapper.from_model(m) for m in models]
|
|
||||||
|
|
||||||
def get_by_titulo(self, titulo: str) -> PostgresCredencial | None:
|
def get_by_titulo(self, titulo: str) -> PostgresCredencial | None:
|
||||||
model = self.session.query(PostgresCredencialModel).filter_by(titulo=titulo).first()
|
model = (
|
||||||
return PostgresCredencialMapper.from_model(model) if model else None
|
self.session.query(self.Modelo)
|
||||||
|
.filter_by(titulo=titulo, sys_deleted_at=None)
|
||||||
def get_by_id(self, id_: int) -> PostgresCredencial | None:
|
.first()
|
||||||
model = self.session.get(PostgresCredencialModel, id_)
|
)
|
||||||
return PostgresCredencialMapper.from_model(model) if model else None
|
return self.Mapper.from_model(model) if model else None
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
from src.Llms.Modelos.Base_model import ModeloABC
|
||||||
|
from src.Llms.Memory.Base_MemoryConv import MemoryConvABC
|
||||||
|
from src.Llms.MCPs.McpClient_Registry import ClientRegistry
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional, List, Union, AsyncGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class AgenteAI:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
modelo: ModeloABC,
|
||||||
|
nombre: str,
|
||||||
|
descripcion: str,
|
||||||
|
system_prompt: str,
|
||||||
|
rol: str,
|
||||||
|
objetivos: List[str],
|
||||||
|
max_iterations: int = 1,
|
||||||
|
memoria: Optional[MemoryConvABC] = None,
|
||||||
|
version: str = "1.0.0",
|
||||||
|
mcp: ClientRegistry = None,
|
||||||
|
output_schema: Optional[dict] = None,
|
||||||
|
):
|
||||||
|
self.modelo = modelo
|
||||||
|
self.memoria = memoria
|
||||||
|
self.output_schema = output_schema
|
||||||
|
|
||||||
|
self.nombre = nombre
|
||||||
|
self.descripcion = descripcion
|
||||||
|
self.system_prompt = system_prompt
|
||||||
|
self.max_iterations = max_iterations
|
||||||
|
self.rol = rol
|
||||||
|
self.objetivos = objetivos
|
||||||
|
self.version = version
|
||||||
|
|
||||||
|
self.created_at = datetime.now()
|
||||||
|
self.updated_at = self.created_at
|
||||||
|
self.numero_interacciones = 0
|
||||||
|
self.mcp = mcp # <-- Aquí guardamos el registry
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def actualizar_configuracion(self, **kwargs):
|
||||||
|
for clave, valor in kwargs.items():
|
||||||
|
if hasattr(self, clave):
|
||||||
|
setattr(self, clave, valor)
|
||||||
|
self.updated_at = datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
async def full_system_prompt(self) -> str:
|
||||||
|
tools_str = await self._obtener_herramientas_disponibles_str()
|
||||||
|
return f"""
|
||||||
|
Eres un agente conversacional con acceso a herramientas MCP (Model Context Protocol).
|
||||||
|
|
||||||
|
Tu comportamiento sigue este flujo:
|
||||||
|
|
||||||
|
1. **Piensa** para razonar tu decisión.
|
||||||
|
2. **Decide** si:
|
||||||
|
- puedes responder tú mismo,
|
||||||
|
- necesitas más información del usuario,
|
||||||
|
- o necesitas una herramienta MCP.
|
||||||
|
3. **Actúa**:
|
||||||
|
- Cuando uses MCP, termina **solo** con un bloque de código MCP y **nada más**.
|
||||||
|
- Ten en cuenta EXACTAMENTE los parámetros especificados.
|
||||||
|
- **No expliques, no hables después del bloque. Termina tu turno.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Formato MCP
|
||||||
|
|
||||||
|
```mcp
|
||||||
|
{{
|
||||||
|
"tool": "<nombre_de_la_herramienta>",
|
||||||
|
"input": {{
|
||||||
|
"clave": "valor"
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
Reglas clave:
|
||||||
|
|
||||||
|
Razonas antes de actuar.
|
||||||
|
|
||||||
|
Nunca hables después de un bloque MCP.
|
||||||
|
|
||||||
|
No combines respuestas y herramientas.
|
||||||
|
|
||||||
|
Piensa. Decide. Actúa.
|
||||||
|
|
||||||
|
Herramientas disponibles para usar con MCP:
|
||||||
|
{tools_str}
|
||||||
|
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Conseguir las herramientas disponibles
|
||||||
|
|
||||||
|
async def _obtener_herramientas_disponibles_str(self) -> str:
|
||||||
|
if not self.mcp:
|
||||||
|
return "No se han definido herramientas disponibles."
|
||||||
|
|
||||||
|
herramientas = []
|
||||||
|
tools_por_cliente = await self.mcp.listar_tools_por_cliente()
|
||||||
|
|
||||||
|
for name, tools in tools_por_cliente.items():
|
||||||
|
if not tools:
|
||||||
|
continue
|
||||||
|
herramientas.append(f"\n🔌 Cliente: {name}")
|
||||||
|
for tool in tools:
|
||||||
|
props = tool.inputSchema.get("properties", {})
|
||||||
|
parametros = "\n ".join(f"- {k} ({v.get('type', '?')})" for k, v in props.items())
|
||||||
|
herramientas.append(f"""Nombre: {tool.name}
|
||||||
|
Descripción: {tool.description}
|
||||||
|
Parámetros:
|
||||||
|
{parametros}
|
||||||
|
""")
|
||||||
|
return "\n".join(herramientas) or "No hay herramientas disponibles actualmente."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Formatear prompt para agentes
|
||||||
|
|
||||||
|
def _formatear_prompt(self, mensajes: List[dict]) -> str:
|
||||||
|
return "\n".join([f"{msg['role']}: {msg['content']}" for msg in mensajes])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###----------- Funcion para interactuar
|
||||||
|
|
||||||
|
async def interactuar(self, prompt: str, stream: bool = False) -> Union[str, AsyncGenerator[str, None]]:
|
||||||
|
historial = self.memoria.cargar_historial_chat() if self.memoria else []
|
||||||
|
contexto = historial + [{"role": "user", "content": prompt}]
|
||||||
|
prompt_final = self._formatear_prompt(contexto)
|
||||||
|
|
||||||
|
respuesta = await self.modelo.responder(
|
||||||
|
prompt=prompt_final,
|
||||||
|
system_prompt=await self.full_system_prompt, # ✅ correcto
|
||||||
|
stream=stream
|
||||||
|
)
|
||||||
|
|
||||||
|
if stream:
|
||||||
|
async def wrapper():
|
||||||
|
buffer_respuesta = ""
|
||||||
|
async for token in respuesta:
|
||||||
|
buffer_respuesta += token
|
||||||
|
yield token
|
||||||
|
if self.memoria:
|
||||||
|
self.memoria.guardar_turno("user", prompt)
|
||||||
|
self.memoria.guardar_turno("assistant", buffer_respuesta)
|
||||||
|
self.numero_interacciones += 1
|
||||||
|
self.updated_at = datetime.now()
|
||||||
|
return wrapper()
|
||||||
|
else:
|
||||||
|
if self.memoria:
|
||||||
|
self.memoria.guardar_turno("user", prompt)
|
||||||
|
self.memoria.guardar_turno("assistant", respuesta)
|
||||||
|
self.numero_interacciones += 1
|
||||||
|
self.updated_at = datetime.now()
|
||||||
|
return respuesta
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###----------- Funcion para interactuar en bucle
|
||||||
|
|
||||||
|
async def interactuar_en_bucle(self, prompt: str, stream: bool = False) -> Union[List[str], AsyncGenerator[str, None]]:
|
||||||
|
print("🚀 [interactuar_en_bucle] Iniciando interacción")
|
||||||
|
historial = self.memoria.cargar_historial_chat() if self.memoria else []
|
||||||
|
print(f"📜 [interactuar_en_bucle] Historial cargado: {historial}")
|
||||||
|
respuestas = [] if not stream else None
|
||||||
|
respuesta_anterior = None
|
||||||
|
iteration = 0
|
||||||
|
prompt_original = prompt.strip()
|
||||||
|
print(f"✏️ [interactuar_en_bucle] Prompt original: {prompt_original}")
|
||||||
|
|
||||||
|
async def generador():
|
||||||
|
nonlocal iteration, respuesta_anterior
|
||||||
|
prompt_actual = prompt_original
|
||||||
|
|
||||||
|
while self.max_iterations == 0 or iteration < self.max_iterations:
|
||||||
|
print(f"\n🔁 [generador] Iteración: {iteration}")
|
||||||
|
|
||||||
|
if iteration == 0:
|
||||||
|
prompt_actual += (
|
||||||
|
"\n\nIMPORTANTE:\n"
|
||||||
|
"Si al revisar tu última respuesta y mi pregunta inicial consideras que has terminado, "
|
||||||
|
"di alguna de estas frases: <END>"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
prompt_actual = (
|
||||||
|
f"Esta es la pregunta original:\n{prompt_original}\n\n"
|
||||||
|
f"Esto fue lo último que dijiste:\n{respuesta_anterior}\n"
|
||||||
|
"\n\nIMPORTANTE:\n"
|
||||||
|
"Si al revisar tu última respuesta y mi pregunta inicial consideras que has terminado, "
|
||||||
|
"di alguna de estas frases: <END>"
|
||||||
|
"En caso contrario, responde a la pregunta original "
|
||||||
|
"y añade información relevante que no hayas mencionado antes.\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
contexto = historial + [{"role": "user", "content": prompt_actual}]
|
||||||
|
prompt_final = self._formatear_prompt(contexto)
|
||||||
|
|
||||||
|
print(f"📨 [generador] Prompt final enviado al modelo:\n{prompt_final}")
|
||||||
|
|
||||||
|
print("🤖 [generador] Esperando respuesta del modelo...")
|
||||||
|
respuesta = await self.modelo.responder(
|
||||||
|
prompt=prompt_final,
|
||||||
|
system_prompt=await self.full_system_prompt,
|
||||||
|
stream=stream
|
||||||
|
)
|
||||||
|
print("✅ [generador] Respuesta recibida")
|
||||||
|
|
||||||
|
if stream:
|
||||||
|
buffer_respuesta = ""
|
||||||
|
async for token in respuesta:
|
||||||
|
buffer_respuesta += token
|
||||||
|
# print(f"🔹 [stream] Token: {token}")
|
||||||
|
yield token
|
||||||
|
respuesta_anterior = buffer_respuesta
|
||||||
|
# print(f"📦 [stream] Respuesta completa:\n{respuesta_anterior}")
|
||||||
|
else:
|
||||||
|
respuestas.append(respuesta)
|
||||||
|
respuesta_anterior = respuesta
|
||||||
|
# print(f"📦 [generador] Respuesta completa:\n{respuesta_anterior}")
|
||||||
|
|
||||||
|
if self.memoria:
|
||||||
|
print("💾 [memoria] Guardando turno en la memoria...")
|
||||||
|
self.memoria.guardar_turno("user", prompt_actual)
|
||||||
|
self.memoria.guardar_turno("assistant", respuesta_anterior)
|
||||||
|
|
||||||
|
self.numero_interacciones += 1
|
||||||
|
self.updated_at = datetime.now()
|
||||||
|
print(f"📊 [generador] Interacción #{self.numero_interacciones} registrada")
|
||||||
|
|
||||||
|
if "<end>" in respuesta_anterior.lower():
|
||||||
|
print("🛑 [generador] Detectado <end>. Terminando bucle.")
|
||||||
|
break
|
||||||
|
|
||||||
|
iteration += 1
|
||||||
|
prompt_actual = ""
|
||||||
|
|
||||||
|
return generador() if stream else await generador_to_list(generador)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Helper para consumir generador asincrónico si no es stream
|
||||||
|
async def generador_to_list(gen: AsyncGenerator[str, None]) -> List[str]:
|
||||||
|
buffer = ""
|
||||||
|
async for chunk in gen:
|
||||||
|
buffer += chunk
|
||||||
|
return [buffer]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
class EmbedderABC(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def encoder(self, text: str) -> List[float]:
|
||||||
|
"""Genera los embeddings para un texto dado."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def dimension_number(self) -> int:
|
||||||
|
"""Devuelve la dimensión del modelo de embedding."""
|
||||||
|
pass
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
from typing import List
|
||||||
|
from src.Llms.Embedders.Base_Embedder import EmbedderABC # Asegúrate de que EmbedderABC esté en este módulo
|
||||||
|
from src.ApiKeys.openai_apikey import OpenAICredencial
|
||||||
|
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||||
|
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||||
|
|
||||||
|
class OpenAIEmbedder(EmbedderABC):
|
||||||
|
def __init__(self, credencial: OpenAICredencial,
|
||||||
|
model: str,
|
||||||
|
id: str = None):
|
||||||
|
self.model = model
|
||||||
|
self.client = OpenAICliente(credencial)
|
||||||
|
self._dimension = None # Lazy loading
|
||||||
|
self.id = id if id is not None else GeneradorIDUnico("OAMB").generar()
|
||||||
|
|
||||||
|
def encoder(self, text: str) -> List[float]:
|
||||||
|
"""
|
||||||
|
Genera los embeddings para un texto dado utilizando el modelo de OpenAI.
|
||||||
|
"""
|
||||||
|
response = self.client.embedding(model=self.model, input=text)
|
||||||
|
embedding = response.data[0].embedding
|
||||||
|
if self._dimension is None:
|
||||||
|
self._dimension = len(embedding)
|
||||||
|
return embedding
|
||||||
|
|
||||||
|
def dimension_number(self) -> int:
|
||||||
|
"""
|
||||||
|
Devuelve la dimensión del modelo de embedding, generando un embedding si no se ha calculado aún.
|
||||||
|
"""
|
||||||
|
if self._dimension is None:
|
||||||
|
_ = self.encoder("dimension_check")
|
||||||
|
return self._dimension
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from sqlalchemy import Column, String
|
||||||
|
from sqlalchemy import Column, String, ForeignKey
|
||||||
|
|
||||||
|
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||||
|
from src.ArquitectureLayer.Model import Model_base
|
||||||
|
from src.ArquitectureLayer.Repo import Repo_base
|
||||||
|
|
||||||
|
from src.ConexionSql.Base_conexion import ConexionBase
|
||||||
|
from src.base import Base
|
||||||
|
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||||
|
from src.Llms.Embedders.Openai_embedder import OpenAIEmbedder
|
||||||
|
from src.ApiKeys.openai_apikey import OpenAICredencial
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# Cargar configuración desde .env si se requiere
|
||||||
|
# ----------------------
|
||||||
|
from entrypoint import ENV_PATH
|
||||||
|
load_dotenv(ENV_PATH)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# MODELO (SQLAlchemy)
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class OpenAIEmbedderModel(Base, Model_base):
|
||||||
|
__tablename__ = "openai_embedders"
|
||||||
|
|
||||||
|
id = Column(String, primary_key=True)
|
||||||
|
|
||||||
|
api_key_id = Column(String, ForeignKey("openai_credenciales.id"), nullable=False)
|
||||||
|
model = Column(String, nullable=False)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# MAPPER
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class OpenAIEmbedderMapper(Mapper_base[OpenAIEmbedder, OpenAIEmbedderModel]):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_model(obj: OpenAIEmbedder) -> OpenAIEmbedderModel:
|
||||||
|
return OpenAIEmbedderModel(
|
||||||
|
id=obj.id,
|
||||||
|
api_key_id=obj.client.credencial.id,
|
||||||
|
model=obj.model
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_model(model: OpenAIEmbedderModel, credencial: OpenAICredencial) -> OpenAIEmbedder:
|
||||||
|
return OpenAIEmbedder(
|
||||||
|
id=model.id,
|
||||||
|
credencial=credencial,
|
||||||
|
model=model.model
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_dict(obj: OpenAIEmbedder) -> dict:
|
||||||
|
return {
|
||||||
|
"id": obj.id,
|
||||||
|
"api_key_id": obj.client.credencial.id,
|
||||||
|
"model": obj.model
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data: dict, credencial: OpenAICredencial) -> OpenAIEmbedder:
|
||||||
|
return OpenAIEmbedder(
|
||||||
|
id=data["id"],
|
||||||
|
credencial=credencial,
|
||||||
|
model=data["model"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# REPO
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class OpenAIEmbedderRepo(Repo_base[OpenAIEmbedderModel, OpenAIEmbedder]):
|
||||||
|
def __init__(self, conexion: ConexionBase):
|
||||||
|
super().__init__(
|
||||||
|
session=conexion.get_session(),
|
||||||
|
modelo=OpenAIEmbedderModel,
|
||||||
|
mapper=OpenAIEmbedderMapper
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_by_id(self, id_: str, credencial: OpenAICredencial) -> OpenAIEmbedder | None:
|
||||||
|
model = self.session.get(self.Modelo, id_)
|
||||||
|
return self.Mapper.from_model(model, credencial) if model else None
|
||||||
|
|
||||||
|
def get_all(self, credencial_loader: callable) -> list[OpenAIEmbedder]:
|
||||||
|
"""
|
||||||
|
:param credencial_loader: función que recibe un api_key_id y devuelve una instancia de OpenAICredencial
|
||||||
|
"""
|
||||||
|
models = self.session.query(self.Modelo).all()
|
||||||
|
return [
|
||||||
|
self.Mapper.from_model(m, credencial_loader(m.api_key_id))
|
||||||
|
for m in models
|
||||||
|
]
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Optional, Union
|
||||||
|
from pydantic import AnyUrl
|
||||||
|
from fastmcp.client import Client
|
||||||
|
from fastmcp.client.transports import (
|
||||||
|
StreamableHttpTransport,
|
||||||
|
PythonStdioTransport,
|
||||||
|
ClientTransport,
|
||||||
|
)
|
||||||
|
from mcp.types import *
|
||||||
|
from fastmcp.exceptions import ClientError
|
||||||
|
|
||||||
|
|
||||||
|
class MCPClient:
|
||||||
|
def __init__(self, name: str, client: Client):
|
||||||
|
self.name = name
|
||||||
|
self.client = client
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<ClientWrapper(name={self.name})>"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_http(cls, name: str, url: str | AnyUrl) -> "MCPClient":
|
||||||
|
transport = StreamableHttpTransport(url=str(url))
|
||||||
|
client = Client(transport=transport)
|
||||||
|
return cls(name=name, client=client)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_stdio(
|
||||||
|
cls,
|
||||||
|
name: str,
|
||||||
|
script_path: Union[str, Path],
|
||||||
|
args: Optional[list[str]] = None,
|
||||||
|
cwd: Optional[Union[str, Path]] = None,
|
||||||
|
env: Optional[dict[str, str]] = None,
|
||||||
|
) -> "MCPClient":
|
||||||
|
transport = PythonStdioTransport(
|
||||||
|
script_path=script_path, args=args, cwd=cwd, env=env
|
||||||
|
)
|
||||||
|
client = Client(transport=transport)
|
||||||
|
return cls(name=name, client=client)
|
||||||
|
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return self.client.is_connected()
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
await self.client.__aenter__()
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
await self.client.__aexit__(exc_type, exc_val, exc_tb)
|
||||||
|
|
||||||
|
# Delegación MCP
|
||||||
|
|
||||||
|
async def call_tool(
|
||||||
|
self, name: str, arguments: dict[str, Any] | None = None
|
||||||
|
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
||||||
|
return await self.client.call_tool(name, arguments)
|
||||||
|
|
||||||
|
async def get_prompt(
|
||||||
|
self, name: str, arguments: dict[str, str] | None = None
|
||||||
|
) -> GetPromptResult:
|
||||||
|
return await self.client.get_prompt(name, arguments)
|
||||||
|
|
||||||
|
async def list_tools(self) -> list[Tool]:
|
||||||
|
return await self.client.list_tools()
|
||||||
|
|
||||||
|
async def list_prompts(self) -> list[Prompt]:
|
||||||
|
return await self.client.list_prompts()
|
||||||
|
|
||||||
|
async def list_resources(self) -> list[Resource]:
|
||||||
|
return await self.client.list_resources()
|
||||||
|
|
||||||
|
async def list_resource_templates(self) -> list[ResourceTemplate]:
|
||||||
|
return await self.client.list_resource_templates()
|
||||||
|
|
||||||
|
async def read_resource(
|
||||||
|
self, uri: AnyUrl | str
|
||||||
|
) -> list[TextResourceContents | BlobResourceContents]:
|
||||||
|
return await self.client.read_resource(uri)
|
||||||
|
|
||||||
|
async def complete(
|
||||||
|
self,
|
||||||
|
ref: ResourceReference | PromptReference,
|
||||||
|
argument: dict[str, str],
|
||||||
|
) -> Completion:
|
||||||
|
return await self.client.complete(ref, argument)
|
||||||
|
|
||||||
|
async def ping(self) -> bool:
|
||||||
|
return await self.client.ping()
|
||||||
|
|
||||||
|
async def set_logging_level(self, level: LoggingLevel) -> None:
|
||||||
|
return await self.client.set_logging_level(level)
|
||||||
|
|
||||||
|
async def send_roots_list_changed(self) -> None:
|
||||||
|
return await self.client.send_roots_list_changed()
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
from src.Llms.MCPs.McpClient import MCPClient
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
class ClientRegistry:
|
||||||
|
def __init__(self):
|
||||||
|
self._clients: dict[str, MCPClient] = {}
|
||||||
|
|
||||||
|
def add(self, name: str, wrapper: MCPClient) -> None:
|
||||||
|
self._clients[name] = wrapper
|
||||||
|
|
||||||
|
def get(self, name: str) -> MCPClient:
|
||||||
|
if name not in self._clients:
|
||||||
|
raise KeyError(f"Cliente '{name}' no encontrado en el registro.")
|
||||||
|
return self._clients[name]
|
||||||
|
|
||||||
|
def all(self) -> dict[str, MCPClient]:
|
||||||
|
return self._clients
|
||||||
|
|
||||||
|
def list_names(self) -> list[str]:
|
||||||
|
return list(self._clients.keys())
|
||||||
|
|
||||||
|
def __contains__(self, name: str) -> bool:
|
||||||
|
return name in self._clients
|
||||||
|
|
||||||
|
async def listar_tools_por_cliente(self) -> dict[str, list[Any]]:
|
||||||
|
resultado = {}
|
||||||
|
for name, wrapper in self._clients.items():
|
||||||
|
try:
|
||||||
|
async with wrapper:
|
||||||
|
resultado[name] = await wrapper.list_tools()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[TOOLS] ❌ Error en '{name}': {e}")
|
||||||
|
resultado[name] = []
|
||||||
|
return resultado
|
||||||
|
|
||||||
|
async def listar_prompts_por_cliente(self) -> dict[str, list[Any]]:
|
||||||
|
resultado = {}
|
||||||
|
for name, wrapper in self._clients.items():
|
||||||
|
try:
|
||||||
|
async with wrapper:
|
||||||
|
resultado[name] = await wrapper.list_prompts()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[PROMPTS] ❌ Error en '{name}': {e}")
|
||||||
|
resultado[name] = []
|
||||||
|
return resultado
|
||||||
|
|
||||||
|
async def listar_resources_por_cliente(self) -> dict[str, list[Any]]:
|
||||||
|
resultado = {}
|
||||||
|
for name, wrapper in self._clients.items():
|
||||||
|
try:
|
||||||
|
async with wrapper:
|
||||||
|
resultado[name] = await wrapper.list_resources()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[RESOURCES] ❌ Error en '{name}': {e}")
|
||||||
|
resultado[name] = []
|
||||||
|
return resultado
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
from fastmcp import FastMCP
|
||||||
|
|
||||||
|
mcp = FastMCP()
|
||||||
|
|
||||||
|
@mcp.tool(description="Suma dos números enteros.")
|
||||||
|
def add(a: int, b: int) -> int:
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
@mcp.tool(description="Resta dos números enteros.")
|
||||||
|
def subtract(a: int, b: int) -> int:
|
||||||
|
return a - b
|
||||||
|
|
||||||
|
@mcp.tool(description="Multiplica dos números enteros.")
|
||||||
|
def multiply(a: int, b: int) -> int:
|
||||||
|
return a * b
|
||||||
|
|
||||||
|
@mcp.tool(description="Divide dos números y devuelve el resultado flotante.")
|
||||||
|
def divide(a: float, b: float) -> float:
|
||||||
|
if b == 0:
|
||||||
|
raise ValueError("No se puede dividir entre cero.")
|
||||||
|
return a / b
|
||||||
|
|
||||||
|
@mcp.tool(description="Calcula el módulo de dos números enteros.")
|
||||||
|
def modulo(a: int, b: int) -> int:
|
||||||
|
return a % b
|
||||||
|
|
||||||
|
@mcp.tool(description="Concatena dos cadenas de texto.")
|
||||||
|
def concat(a: str, b: str) -> str:
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve la longitud de una cadena.")
|
||||||
|
def string_length(s: str) -> int:
|
||||||
|
return len(s)
|
||||||
|
|
||||||
|
@mcp.tool(description="Convierte una cadena a mayúsculas.")
|
||||||
|
def to_upper(s: str) -> str:
|
||||||
|
return s.upper()
|
||||||
|
|
||||||
|
@mcp.tool(description="Convierte una cadena a minúsculas.")
|
||||||
|
def to_lower(s: str) -> str:
|
||||||
|
return s.lower()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve la suma de todos los elementos en una lista de enteros.")
|
||||||
|
def sum_list(numbers: list[int]) -> int:
|
||||||
|
return sum(numbers)
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el valor máximo en una lista de enteros.")
|
||||||
|
def max_in_list(numbers: list[int]) -> int:
|
||||||
|
return max(numbers)
|
||||||
|
|
||||||
|
@mcp.tool(description="Verifica si un número es par.")
|
||||||
|
def is_even(n: int) -> bool:
|
||||||
|
return n % 2 == 0
|
||||||
|
|
||||||
|
@mcp.tool(description="Verifica si una cadena es un palíndromo.")
|
||||||
|
def is_palindrome(s: str) -> bool:
|
||||||
|
return s == s[::-1]
|
||||||
|
|
||||||
|
@mcp.tool(description="Calcula el factorial de un número entero positivo.")
|
||||||
|
def factorial(n: int) -> int:
|
||||||
|
if n < 0:
|
||||||
|
raise ValueError("El factorial no está definido para negativos.")
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
result = 1
|
||||||
|
for i in range(1, n + 1):
|
||||||
|
result *= i
|
||||||
|
return result
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve los primeros n números de Fibonacci.")
|
||||||
|
def fibonacci(n: int) -> list[int]:
|
||||||
|
if n <= 0:
|
||||||
|
return []
|
||||||
|
seq = [0, 1]
|
||||||
|
while len(seq) < n:
|
||||||
|
seq.append(seq[-1] + seq[-2])
|
||||||
|
return seq[:n]
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve si un número es primo.")
|
||||||
|
def is_prime(n: int) -> bool:
|
||||||
|
if n <= 1:
|
||||||
|
return False
|
||||||
|
for i in range(2, int(n**0.5) + 1):
|
||||||
|
if n % i == 0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# mcp.run(transport="streamable-http", host="127.0.0.1", port=4200, path="/math")
|
||||||
|
|
||||||
|
mcp.run(transport="stdio")
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
from fastmcp import FastMCP
|
||||||
|
import uuid
|
||||||
|
import datetime
|
||||||
|
import socket
|
||||||
|
import platform
|
||||||
|
import os
|
||||||
|
|
||||||
|
mcp = FastMCP()
|
||||||
|
|
||||||
|
@mcp.tool(description="Genera un UUID versión 4.")
|
||||||
|
def generate_uuid() -> str:
|
||||||
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve la fecha y hora actuales en formato ISO 8601.")
|
||||||
|
def current_datetime() -> str:
|
||||||
|
return datetime.datetime.now().isoformat()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve solo la fecha actual.")
|
||||||
|
def current_date() -> str:
|
||||||
|
return datetime.date.today().isoformat()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el nombre del host actual.")
|
||||||
|
def get_hostname() -> str:
|
||||||
|
return socket.gethostname()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el sistema operativo actual.")
|
||||||
|
def get_os() -> str:
|
||||||
|
return platform.system()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el nombre del usuario actual del sistema.")
|
||||||
|
def get_current_user() -> str:
|
||||||
|
return os.getlogin()
|
||||||
|
|
||||||
|
@mcp.tool(description="Invierte un valor booleano.")
|
||||||
|
def invert_boolean(flag: bool) -> bool:
|
||||||
|
return not flag
|
||||||
|
|
||||||
|
# @mcp.tool(description="Devuelve los archivos y carpetas del directorio actual.")
|
||||||
|
# def list_current_directory() -> list[str]:
|
||||||
|
# return os.listdir()
|
||||||
|
|
||||||
|
# @mcp.tool(description="Crea un archivo con un nombre dado.")
|
||||||
|
# def create_file(filename: str) -> str:
|
||||||
|
# with open(filename, "w") as f:
|
||||||
|
# f.write("")
|
||||||
|
# return f"Archivo '{filename}' creado."
|
||||||
|
|
||||||
|
# @mcp.tool(description="Lee el contenido de un archivo de texto dado.")
|
||||||
|
# def read_file(filename: str) -> str:
|
||||||
|
# with open(filename, "r") as f:
|
||||||
|
# return f.read()
|
||||||
|
|
||||||
|
# @mcp.tool(description="Escribe contenido a un archivo, sobrescribiéndolo.")
|
||||||
|
# def write_file(filename: str, content: str) -> str:
|
||||||
|
# with open(filename, "w") as f:
|
||||||
|
# f.write(content)
|
||||||
|
# return f"Contenido escrito en '{filename}'."
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el número de CPUs disponibles en el sistema.")
|
||||||
|
def get_cpu_count() -> int:
|
||||||
|
return os.cpu_count()
|
||||||
|
|
||||||
|
@mcp.tool(description="Devuelve el timestamp actual (UNIX).")
|
||||||
|
def current_timestamp() -> float:
|
||||||
|
return datetime.datetime.now().timestamp()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
mcp.run(transport="streamable-http", host="127.0.0.1", port=4300, path="/tools")
|
||||||
@@ -3,7 +3,7 @@ from typing import Literal
|
|||||||
|
|
||||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||||
from src.ConexionSql.Postgres_conexion import PostgresConexion # Usamos la clase específica
|
from src.ConexionSql.Postgres_conexion import PostgresConexion # Usamos la clase específica
|
||||||
from llms.Memory.Base_MemoryConv import MemoryConvABC
|
from src.Llms.Memory.Base_MemoryConv import MemoryConvABC
|
||||||
|
|
||||||
|
|
||||||
class MemoryConvPostgres(MemoryConvABC):
|
class MemoryConvPostgres(MemoryConvABC):
|
||||||
@@ -27,7 +27,7 @@ class MemoryConvPostgres(MemoryConvABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Crea la tabla si no existe
|
# Crea la tabla si no existe
|
||||||
self.metadata.create_all(self.conexion.engine)
|
self.metadata.create_all(self.conexion._engine)
|
||||||
|
|
||||||
def guardar_turno(self, rol: Literal["user", "assistant"], contenido: str) -> None:
|
def guardar_turno(self, rol: Literal["user", "assistant"], contenido: str) -> None:
|
||||||
stmt = insert(self.tabla).values(rol=rol, contenido=contenido)
|
stmt = insert(self.tabla).values(rol=rol, contenido=contenido)
|
||||||
@@ -22,7 +22,7 @@ class ModeloABC(ABC):
|
|||||||
self.num_tokens_maximos = num_tokens_maximos
|
self.num_tokens_maximos = num_tokens_maximos
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def responder(self, prompt: str, system_prompt: str = "", **kwargs) -> str:
|
async def responder(self, prompt: str, system_prompt: str = "", stream: bool = False, **kwargs) -> str:
|
||||||
"""
|
"""
|
||||||
Devuelve una respuesta a partir de un prompt y configuración del modelo.
|
Devuelve una respuesta a partir de un prompt y configuración del modelo.
|
||||||
Este método debe implementarse de forma asíncrona en las subclases.
|
Este método debe implementarse de forma asíncrona en las subclases.
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
from src.Llms.Modelos.Base_model import ModeloABC
|
||||||
|
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||||
|
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||||
|
import asyncio
|
||||||
|
from typing import AsyncGenerator, Union
|
||||||
|
|
||||||
|
class ModeloOpenAI(ModeloABC):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
cliente: OpenAICliente,
|
||||||
|
model: str = "gpt-4o",
|
||||||
|
id: str = None,
|
||||||
|
temperature: float = 0.7,
|
||||||
|
top_p: float = 1.0,
|
||||||
|
top_k: int = None,
|
||||||
|
frecuencia_penalizacion: float = 0.0,
|
||||||
|
num_tokens_maximos: int = 512,
|
||||||
|
use_legacy: bool = False
|
||||||
|
):
|
||||||
|
# Generar ID con prefijo MOPA si no fue proporcionado
|
||||||
|
self.id = id if id is not None else GeneradorIDUnico("MOPA").generar()
|
||||||
|
|
||||||
|
# Inicializar resto del modelo base
|
||||||
|
super().__init__(
|
||||||
|
model=model,
|
||||||
|
temperature=temperature,
|
||||||
|
top_p=top_p,
|
||||||
|
top_k=top_k,
|
||||||
|
frecuencia_penalizacion=frecuencia_penalizacion,
|
||||||
|
num_tokens_maximos=num_tokens_maximos
|
||||||
|
)
|
||||||
|
|
||||||
|
# Asignar cliente e indicadores adicionales
|
||||||
|
self.cliente = cliente
|
||||||
|
self.use_legacy = use_legacy
|
||||||
|
|
||||||
|
async def responder(
|
||||||
|
self,
|
||||||
|
prompt: str,
|
||||||
|
system_prompt: str = "",
|
||||||
|
stream: bool = False,
|
||||||
|
**kwargs
|
||||||
|
) -> Union[str, AsyncGenerator[str, None]]:
|
||||||
|
if self.use_legacy:
|
||||||
|
if stream:
|
||||||
|
raise NotImplementedError("El modo legacy no soporta streaming.")
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
respuesta = await loop.run_in_executor(
|
||||||
|
None,
|
||||||
|
lambda: self.cliente.completion(
|
||||||
|
model=self.model,
|
||||||
|
prompt=prompt,
|
||||||
|
temperature=self.temperature,
|
||||||
|
top_p=self.top_p,
|
||||||
|
max_tokens=self.num_tokens_maximos,
|
||||||
|
frequency_penalty=self.frecuencia_penalizacion,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return respuesta.choices[0].text.strip()
|
||||||
|
|
||||||
|
# Construcción de mensajes estilo Chat
|
||||||
|
messages = []
|
||||||
|
if system_prompt:
|
||||||
|
messages.append({"role": "system", "content": system_prompt})
|
||||||
|
messages.append({"role": "user", "content": prompt})
|
||||||
|
|
||||||
|
def sync_call():
|
||||||
|
return self.cliente.chat_completion(
|
||||||
|
model=self.model,
|
||||||
|
messages=messages,
|
||||||
|
temperature=self.temperature,
|
||||||
|
top_p=self.top_p,
|
||||||
|
max_tokens=self.num_tokens_maximos,
|
||||||
|
frequency_penalty=self.frecuencia_penalizacion,
|
||||||
|
stream=stream,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
resultado = await loop.run_in_executor(None, sync_call)
|
||||||
|
|
||||||
|
if stream:
|
||||||
|
async def generador():
|
||||||
|
for token in resultado:
|
||||||
|
yield token
|
||||||
|
return generador()
|
||||||
|
else:
|
||||||
|
return resultado.choices[0].message.content
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from sqlalchemy import Column, Integer, String, Float, Boolean
|
||||||
|
|
||||||
|
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||||
|
from src.ArquitectureLayer.Model import Model_base
|
||||||
|
from src.ArquitectureLayer.Repo import Repo_base
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
from src.ConexionSql.Base_conexion import ConexionBase
|
||||||
|
from src.base import Base
|
||||||
|
from src.Llms.Modelos.Openai_model import ModeloOpenAI # Clase real de lógica
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# Cargar clave maestra
|
||||||
|
# ----------------------
|
||||||
|
from entrypoint import ENV_PATH
|
||||||
|
load_dotenv(ENV_PATH)
|
||||||
|
pssword = os.getenv('MASTER_PASSWORD')
|
||||||
|
if pssword is None:
|
||||||
|
raise ValueError("MASTER_PASSWORD no está definida en el archivo .env")
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# MODELO (SQLAlchemy)
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class ModeloOpenAIConfigModel(Base, Model_base):
|
||||||
|
__tablename__ = 'modelo_openai_configs'
|
||||||
|
|
||||||
|
id = Column(String, primary_key=True)
|
||||||
|
|
||||||
|
model = Column(String, nullable=False)
|
||||||
|
temperature = Column(Float, default=0.7, nullable=False)
|
||||||
|
top_p = Column(Float, default=1.0, nullable=False)
|
||||||
|
top_k = Column(Integer, nullable=True)
|
||||||
|
|
||||||
|
frecuencia_penalizacion = Column(Float, default=0.0, nullable=False)
|
||||||
|
num_tokens_maximos = Column(Integer, default=512, nullable=False)
|
||||||
|
|
||||||
|
use_legacy = Column(Boolean, default=False, nullable=False)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# MAPPER
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class ModeloOpenAIConfigMapper(Mapper_base[ModeloOpenAI, ModeloOpenAIConfigModel]):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_model(obj: ModeloOpenAI) -> ModeloOpenAIConfigModel:
|
||||||
|
return ModeloOpenAIConfigModel(
|
||||||
|
id=obj.id,
|
||||||
|
model=obj.model,
|
||||||
|
temperature=obj.temperature,
|
||||||
|
top_p=obj.top_p,
|
||||||
|
top_k=obj.top_k,
|
||||||
|
frecuencia_penalizacion=obj.frecuencia_penalizacion,
|
||||||
|
num_tokens_maximos=obj.num_tokens_maximos,
|
||||||
|
use_legacy=obj.use_legacy
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_model(model: ModeloOpenAIConfigModel, cliente: Optional[object] = None) -> ModeloOpenAI:
|
||||||
|
return ModeloOpenAI(
|
||||||
|
id=model.id,
|
||||||
|
cliente=cliente,
|
||||||
|
model=model.model,
|
||||||
|
temperature=model.temperature,
|
||||||
|
top_p=model.top_p,
|
||||||
|
top_k=model.top_k,
|
||||||
|
frecuencia_penalizacion=model.frecuencia_penalizacion,
|
||||||
|
num_tokens_maximos=model.num_tokens_maximos,
|
||||||
|
use_legacy=model.use_legacy
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_dict(obj: ModeloOpenAI) -> dict:
|
||||||
|
return {
|
||||||
|
"id": obj.id,
|
||||||
|
"model": obj.model,
|
||||||
|
"temperature": obj.temperature,
|
||||||
|
"top_p": obj.top_p,
|
||||||
|
"top_k": obj.top_k,
|
||||||
|
"frecuencia_penalizacion": obj.frecuencia_penalizacion,
|
||||||
|
"num_tokens_maximos": obj.num_tokens_maximos,
|
||||||
|
"use_legacy": obj.use_legacy
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data: dict, cliente: Optional[object] = None) -> ModeloOpenAI:
|
||||||
|
return ModeloOpenAI(
|
||||||
|
id=data["id"],
|
||||||
|
cliente=cliente,
|
||||||
|
model=data["model"],
|
||||||
|
temperature=data["temperature"],
|
||||||
|
top_p=data["top_p"],
|
||||||
|
top_k=data["top_k"],
|
||||||
|
frecuencia_penalizacion=data["frecuencia_penalizacion"],
|
||||||
|
num_tokens_maximos=data["num_tokens_maximos"],
|
||||||
|
use_legacy=data["use_legacy"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ----------------------
|
||||||
|
# REPO
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
|
class ModeloOpenAIConfigRepo(Repo_base[ModeloOpenAIConfigModel, ModeloOpenAI]):
|
||||||
|
def __init__(self, conexion: ConexionBase, cliente: object):
|
||||||
|
super().__init__(
|
||||||
|
session=conexion.get_session(),
|
||||||
|
modelo=ModeloOpenAIConfigModel,
|
||||||
|
mapper=ModeloOpenAIConfigMapper
|
||||||
|
)
|
||||||
|
self.cliente = cliente # Necesario para construir el dominio con lógica
|
||||||
|
|
||||||
|
def get_by_id(self, id_: str) -> ModeloOpenAI | None:
|
||||||
|
model = self.session.get(self.Modelo, id_)
|
||||||
|
return self.Mapper.from_model(model, self.cliente) if model else None
|
||||||
|
|
||||||
|
def get_all(self) -> list[ModeloOpenAI]:
|
||||||
|
models = self.session.query(self.Modelo).all()
|
||||||
|
return [self.Mapper.from_model(m, self.cliente) for m in models]
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import uuid
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
|
class GeneradorIDUnico:
|
||||||
|
def __init__(self, tipo_objeto: str):
|
||||||
|
if not re.match(r'^[A-Z]{4}$', tipo_objeto):
|
||||||
|
raise ValueError("El tipo de objeto debe tener 4 letras en mayúscula (ej: ABCD)")
|
||||||
|
self.tipo_objeto = tipo_objeto
|
||||||
|
|
||||||
|
def generar(self):
|
||||||
|
f = datetime.datetime.now().strftime('%Y%m%d')
|
||||||
|
u = uuid.uuid4().hex[:9]
|
||||||
|
n = ''.join(filter(str.isdigit, uuid.uuid4().hex))[:8]
|
||||||
|
n = n.ljust(8, '0')
|
||||||
|
t = sum(int(c) for c in f)
|
||||||
|
t += sum(int(c, 16) for c in u)
|
||||||
|
t += sum(int(c) for c in n)
|
||||||
|
c = str(t % 10)
|
||||||
|
l = t + int(c)
|
||||||
|
d = hex(l % 16)[-1]
|
||||||
|
|
||||||
|
return f"{self.tipo_objeto}{f}-{d}{u}{c}{n}"
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def verificar(id_: str) -> bool:
|
||||||
|
try:
|
||||||
|
f = id_[4:12]
|
||||||
|
cuerpo = id_[13:]
|
||||||
|
d = cuerpo[0]
|
||||||
|
u = cuerpo[1:10]
|
||||||
|
c = cuerpo[10]
|
||||||
|
n = cuerpo[11:19]
|
||||||
|
t = sum(int(c) for c in f)
|
||||||
|
t += sum(int(c, 16) for c in u)
|
||||||
|
t += sum(int(c) for c in n)
|
||||||
|
esd = str(t % 10)
|
||||||
|
l = t + int(esd)
|
||||||
|
esh = hex(l % 16)[-1]
|
||||||
|
return (
|
||||||
|
d.lower() == esh.lower() and
|
||||||
|
c == esd
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def tamaño_bytes_bits(id_: str):
|
||||||
|
"""Devuelve el tamaño del ID en bytes y bits (UTF-8)"""
|
||||||
|
bytes_ = len(id_.encode('utf-8'))
|
||||||
|
return bytes_, bytes_ * 8
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Ejemplo de uso
|
||||||
|
generador = GeneradorIDUnico("FACT")
|
||||||
|
nuevo_id = generador.generar()
|
||||||
|
print(f"Nuevo ID generado: {nuevo_id}")
|
||||||
|
|
||||||
|
# Verificación del ID
|
||||||
|
es_valido = GeneradorIDUnico.verificar(nuevo_id)
|
||||||
|
print(f"El ID es válido: {es_valido}")
|
||||||
|
|
||||||
|
# Tamaño del ID
|
||||||
|
bytes_, bits_ = GeneradorIDUnico.tamaño_bytes_bits(nuevo_id)
|
||||||
|
print(f"Tamaño del ID: {bytes_} bytes / {bits_} bits")
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user