Compare commits
14 Commits
e1b756ac99
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fa33321ff1 | |||
| a2873e4c85 | |||
| 0d97aa2d61 | |||
| 23f25034ad | |||
| 8ad80defcf | |||
| aef8791151 | |||
| 3d5deef0fb | |||
| 3438102dc0 | |||
| 9ee8daa295 | |||
| 6d6fab5634 | |||
| 9c638fc3e5 | |||
| 43f6fb03fe | |||
| ac83907e7c | |||
| 3cd267ee6e |
@@ -17,6 +17,7 @@ pruebas_conceptos/postgres_extensions/pgdata/*
|
||||
*.env
|
||||
config/.env
|
||||
|
||||
.continue
|
||||
|
||||
#Icon files
|
||||
frontend/src/assets/icons/filled/** */
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Inicia el frontend en una nueva ventana de PowerShell
|
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", 'cd ./frontend; npm run dev; pause'
|
||||
|
||||
# Inicia el backend en una nueva ventana de PowerShell
|
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", 'cd ./backend; uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000; pause'
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# backend/api/router.py
|
||||
|
||||
from fastapi import APIRouter
|
||||
from backend.api.v1.endpoints import ping, text_manager_endpoint, charts_examples as charts
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
router.include_router(ping.router, prefix="/api/v1/ping")
|
||||
router.include_router(text_manager_endpoint.router, prefix="/api/v1/text_manager")
|
||||
router.include_router(charts.router, prefix="/api/v1/charts")
|
||||
@@ -0,0 +1,44 @@
|
||||
# backend/domains/llm/agent_endpoints.py
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
|
||||
from backend.backend_domains.llms.llm_chat_srvc import construir_agente_llm, responder, responder_stream
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
from entrypoint.init_db import db_credencial
|
||||
|
||||
LoggerDB(db_credencial, "logger_llm", created_by="sistema")
|
||||
|
||||
router = APIRouter()
|
||||
agente = construir_agente_llm() # inicializa el agente una vez
|
||||
|
||||
# 📥 Schema para entrada de prompt
|
||||
class ChatInput(BaseModel):
|
||||
prompt: str
|
||||
|
||||
# ✅ Endpoint de respuesta simple
|
||||
@router.post("/chat", summary="Enviar prompt y obtener respuesta completa del agente")
|
||||
async def chat_endpoint(data: ChatInput):
|
||||
try:
|
||||
return await responder(data.prompt, agente)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.exception("[ERROR] Fallo durante respuesta del agente:")
|
||||
raise HTTPException(status_code=500, detail="Error interno al procesar la solicitud.")
|
||||
|
||||
# 🔁 Endpoint de streaming
|
||||
@router.post("/chat-stream", summary="Enviar prompt y recibir respuesta del agente en streaming")
|
||||
async def chat_stream_endpoint(data: ChatInput):
|
||||
try:
|
||||
return StreamingResponse(
|
||||
responder_stream(data.prompt, agente),
|
||||
media_type="text/plain"
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.exception("[ERROR] Fallo durante respuesta en streaming:")
|
||||
raise HTTPException(status_code=500, detail="Error interno en el agente.")
|
||||
@@ -0,0 +1,84 @@
|
||||
# src/services/agent_service.py
|
||||
|
||||
from domains.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from domains.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||
from domains.Llms.Modelos.Openai_model import ModeloOpenAI
|
||||
from domains.Llms.Agente import AgenteAI
|
||||
from domains.Llms.Memory.postgres_MemoryConv import MemoryConvPostgres
|
||||
from domains.Llms.MCPs.McpClient import MCPClient
|
||||
from domains.Llms.MCPs.McpClient_Registry import ClientRegistry
|
||||
from entrypoint.init_db import db_credencial
|
||||
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
LoggerDB(db_credencial, "logger_llm", created_by="sistema")
|
||||
|
||||
from typing import AsyncGenerator
|
||||
|
||||
# 🔧 Inicialización única del agente
|
||||
def construir_agente_llm() -> AgenteAI:
|
||||
logger.info("[INICIO] Inicializando agente LLM...")
|
||||
|
||||
conexion = PostgresConexion(db_credencial)
|
||||
|
||||
# Paso 1: Obtener credencial
|
||||
repo = OpenAICredencialRepo(conexion)
|
||||
credencial = repo.get_by_id("OPAK20250513-61b29978b7604031014")
|
||||
if not credencial:
|
||||
raise ValueError("No se encontró la credencial OpenAI")
|
||||
|
||||
logger.debug(f"[OK] Credencial OpenAI cargada: {credencial.titulo}")
|
||||
|
||||
# Paso 2: Crear cliente
|
||||
cliente = OpenAICliente(credencial)
|
||||
|
||||
# Paso 3: Instanciar modelo
|
||||
modelo = ModeloOpenAI(
|
||||
cliente=cliente,
|
||||
model="gpt-4o",
|
||||
temperature=1
|
||||
)
|
||||
|
||||
# Paso 4: Memoria en PostgreSQL
|
||||
memoria = MemoryConvPostgres(
|
||||
credencial=db_credencial,
|
||||
nombre_tabla="memoria_conversacion_pruebas",
|
||||
k=10
|
||||
)
|
||||
|
||||
# Paso 5: Herramientas MCP (ej. archivos)
|
||||
archivos = MCPClient.from_http(
|
||||
name="files",
|
||||
url="http://127.0.0.1:4201/fs"
|
||||
)
|
||||
registry = ClientRegistry()
|
||||
registry.add("files", archivos)
|
||||
|
||||
# Paso 6: Agente
|
||||
agente = AgenteAI(
|
||||
modelo=modelo,
|
||||
nombre="Asistente Inteligente",
|
||||
descripcion="",
|
||||
system_prompt="",
|
||||
rol="asistente",
|
||||
objetivos=[],
|
||||
max_iterations=0,
|
||||
memoria=memoria,
|
||||
mcp=registry
|
||||
)
|
||||
|
||||
logger.success("[OK] Agente LLM listo.")
|
||||
return agente
|
||||
|
||||
# ⚡ Función simple
|
||||
async def responder(prompt: str, agente: AgenteAI) -> str:
|
||||
logger.info(f"[Petición] Prompt recibido: {prompt[:50]}...")
|
||||
respuesta = await agente.interactuar_en_bucle(prompt=prompt, stream=False)
|
||||
logger.debug(f"[Respuesta] {respuesta[:100]}...")
|
||||
return respuesta
|
||||
|
||||
# 🔁 Función en streaming
|
||||
async def responder_stream(prompt: str, agente: AgenteAI) -> AsyncGenerator[str, None]:
|
||||
logger.info(f"[Streaming] Prompt recibido: {prompt[:50]}...")
|
||||
async for token in agente.interactuar_en_bucle(prompt=prompt, stream=True):
|
||||
yield token
|
||||
@@ -0,0 +1,35 @@
|
||||
from fastapi import WebSocket, APIRouter, WebSocketDisconnect
|
||||
from backend.backend_domains.llms.llm_chat_srvc import construir_agente_llm
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
from entrypoint.init_db import db_credencial
|
||||
import json
|
||||
|
||||
LoggerDB(db_credencial, "logger_llm_ws", created_by="sistema")
|
||||
|
||||
router = APIRouter()
|
||||
agente = construir_agente_llm()
|
||||
|
||||
@router.websocket("/ws/chat")
|
||||
async def chat_ws(websocket: WebSocket):
|
||||
await websocket.accept()
|
||||
try:
|
||||
data = await websocket.receive_text()
|
||||
parsed = json.loads(data)
|
||||
prompt = parsed.get("prompt")
|
||||
if not prompt:
|
||||
await websocket.send_text("⚠️ Prompt vacío.")
|
||||
await websocket.close()
|
||||
return
|
||||
|
||||
# ✅ Solución: hacer await antes de iterar
|
||||
respuesta_gen = await agente.interactuar_en_bucle(prompt=prompt, stream=True)
|
||||
async for token in respuesta_gen:
|
||||
await websocket.send_text(token)
|
||||
|
||||
await websocket.close()
|
||||
|
||||
except WebSocketDisconnect:
|
||||
logger.info("🔌 WebSocket desconectado por el cliente.")
|
||||
except Exception as e:
|
||||
logger.exception("❌ Error en WebSocket:")
|
||||
await websocket.close()
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from backend.api.v1.router import router
|
||||
from backend.backend_domains.router_v1 import router
|
||||
from backend.backend_domains.llms import llm_chat_ws_endpoint_v1
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="Fitz Backend",
|
||||
@@ -21,4 +23,5 @@ app.add_middleware(
|
||||
|
||||
|
||||
# Incluye las rutas de tu API
|
||||
app.include_router(router)
|
||||
app.include_router(router, prefix="/api/v1", tags=["v1"])
|
||||
app.include_router(llm_chat_ws_endpoint_v1.router)
|
||||
@@ -0,0 +1,15 @@
|
||||
# backend/api/router_v1.py
|
||||
|
||||
from fastapi import APIRouter
|
||||
from backend.backend_domains.experiments import charts_examples_endpoint_v1 as charts
|
||||
from backend.backend_domains.experiments import ping_endpoint_v1
|
||||
from backend.backend_domains.text_manager import text_manager_endpoint_v1
|
||||
from backend.backend_domains.llms import llm_chat_endpoint_v1
|
||||
from backend.backend_domains.usuarios_endpoint_v1 import router as usuarios_router
|
||||
|
||||
router = APIRouter()
|
||||
router.include_router(ping_endpoint_v1.router, prefix="/ping")
|
||||
router.include_router(text_manager_endpoint_v1.router, prefix="/text_manager")
|
||||
router.include_router(charts.router, prefix="/charts")
|
||||
router.include_router(llm_chat_endpoint_v1.router, prefix="/llm", tags=["Agente LLM"])
|
||||
router.include_router(usuarios_router, prefix="/usuarios", tags=["Usuarios"])
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import Path
|
||||
|
||||
from backend.schemas.text_manager_schema import BibliotecaInput, NotaInput
|
||||
from backend.backend_domains.text_manager.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
|
||||
from backend.backend_domains.text_manager.text_manager_srvc import *
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
|
||||
from entrypoint.init_db import db_credencial
|
||||
from src.Logger.logger_db import LoggerDB, logger
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
LoggerDB(db_credencial, "logger_textos", created_by="sistema")
|
||||
|
||||
router = APIRouter()
|
||||
+9
-9
@@ -1,15 +1,15 @@
|
||||
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 domains.TextManager.biblioteca import Biblioteca
|
||||
from domains.TextManager.biblioteca_mmr import BibliotecaRepo
|
||||
from domains.Llms.Embedders.Openai_embedder import OpenAIEmbedder
|
||||
from domains.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from domains.TextManager.nota import Nota
|
||||
from domains.TextManager.notas_mmr import generar_tabla_nota_para_biblioteca, NotaRepo
|
||||
from sqlalchemy import MetaData
|
||||
from backend.schemas.text_manager_schema import NotaInput
|
||||
from backend.backend_domains.text_manager.text_manager_schema import NotaInput
|
||||
|
||||
from entrypoint.init_db import db_credencial
|
||||
from src.Logger.logger_db import LoggerDB, logger
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
LoggerDB(db_credencial, "logger_textos", created_by="sistema")
|
||||
|
||||
def crear_biblioteca(nombre_biblioteca: str, conexion: PostgresConexion, descripcion: str = None):
|
||||
@@ -0,0 +1,35 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from domains.Usuario.usuario_mmr import UsuarioRepo, Usuario, UsuarioModel
|
||||
from backend.db.conexion import get_conexion
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/usuarios/", response_model=dict)
|
||||
def crear_usuario(nombre: str, email: str, db: Session = Depends(get_conexion)):
|
||||
repo = UsuarioRepo(db)
|
||||
usuario = Usuario(id=None, nombre=nombre, email=email)
|
||||
usuario_id = repo.add(usuario)
|
||||
return {"id": usuario_id}
|
||||
|
||||
@router.get("/usuarios/{usuario_id}", response_model=dict)
|
||||
def obtener_usuario(usuario_id: int, db: Session = Depends(get_conexion)):
|
||||
repo = UsuarioRepo(db)
|
||||
usuario = repo.get_by_id(usuario_id)
|
||||
if not usuario:
|
||||
raise HTTPException(status_code=404, detail="Usuario no encontrado")
|
||||
return {"id": usuario.id, "nombre": usuario.nombre, "email": usuario.email, "activo": usuario.activo}
|
||||
|
||||
@router.get("/usuarios/", response_model=list)
|
||||
def listar_usuarios(db: Session = Depends(get_conexion)):
|
||||
repo = UsuarioRepo(db)
|
||||
usuarios = repo.get_all()
|
||||
return [{"id": u.id, "nombre": u.nombre, "email": u.email, "activo": u.activo} for u in usuarios]
|
||||
|
||||
@router.delete("/usuarios/{usuario_id}", response_model=dict)
|
||||
def eliminar_usuario(usuario_id: int, db: Session = Depends(get_conexion)):
|
||||
repo = UsuarioRepo(db)
|
||||
exito = repo.delete_by_id(usuario_id)
|
||||
if not exito:
|
||||
raise HTTPException(status_code=404, detail="Usuario no encontrado")
|
||||
return {"ok": True}
|
||||
@@ -1,6 +1,6 @@
|
||||
# backend/db/conexion.py
|
||||
from entrypoint.init_db import db_credencial
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
|
||||
def get_conexion():
|
||||
conexion = PostgresConexion(db_credencial)
|
||||
|
||||
+26
-1016
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
|
||||
class OpenAICredencial:
|
||||
def __init__(self, titulo: str, api_key: str, organizacion: str = None, id: str = None):
|
||||
@@ -3,17 +3,17 @@ import base64
|
||||
from dotenv import load_dotenv
|
||||
from sqlalchemy import Column, Integer, String
|
||||
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from src.base import Base
|
||||
from src.ApiKeys.openai_apikey import OpenAICredencial
|
||||
from src.Security.Encriptar import Encriptar_fernet
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.base import Base
|
||||
from domains.ApiKeys.openai_apikey import OpenAICredencial
|
||||
from domains.Security.Encriptar import Encriptar_fernet
|
||||
from entrypoint import ENV_PATH
|
||||
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
|
||||
|
||||
from sqlalchemy import Column, String
|
||||
from src.ArquitectureLayer.Model import Model_base
|
||||
from src.ArquitectureLayer.Repo import Repo_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ArquitectureLayer.Repo import Repo_base
|
||||
|
||||
|
||||
# ----------------------
|
||||
@@ -6,7 +6,7 @@ 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
|
||||
from domains.ArquitectureLayer.Mapper import Mapper_base # Asegúrate de importar tu ABC base
|
||||
|
||||
TModelo = TypeVar("TModelo")
|
||||
TDominio = TypeVar("TDominio")
|
||||
@@ -1,5 +1,5 @@
|
||||
import requests
|
||||
from src.Credenciales.ollama_credencial import OllamaCredencial
|
||||
from domains.Credenciales.ollama_credencial import OllamaCredencial
|
||||
|
||||
class OllamaCliente:
|
||||
def __init__(self, credencial: OllamaCredencial):
|
||||
@@ -1,5 +1,5 @@
|
||||
from openai import OpenAI
|
||||
from src.ApiKeys.openai_apikey import OpenAICredencial
|
||||
from domains.ApiKeys.openai_apikey import OpenAICredencial
|
||||
|
||||
class OpenAICliente:
|
||||
def __init__(self, credencial: OpenAICredencial):
|
||||
@@ -4,8 +4,8 @@ from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import sessionmaker, Session
|
||||
from sqlalchemy.engine import Engine
|
||||
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial
|
||||
|
||||
class PostgresConexion(ConexionBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -1,4 +1,4 @@
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
|
||||
class OllamaCredencial:
|
||||
def __init__(self, titulo: str, base_url: str = "http://localhost:11434", id: str = None):
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
|
||||
class PostgresCredencial:
|
||||
def __init__(self, titulo: str, host: str, port: int, dbname: str, user: str, password: str, id: str = None):
|
||||
+7
-7
@@ -6,14 +6,14 @@ 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 domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ArquitectureLayer.Repo import Repo_base
|
||||
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from src.base import Base
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from src.Security.Encriptar import Encriptar_fernet
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.base import Base
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from domains.Security.Encriptar import Encriptar_fernet
|
||||
|
||||
# ----------------------
|
||||
# Cargar clave maestra
|
||||
@@ -1,13 +1,13 @@
|
||||
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 domains.Llms.Modelos.Base_model import ModeloABC
|
||||
from domains.Llms.Memory.Base_MemoryConv import MemoryConvABC
|
||||
from domains.Llms.MCPs.McpClient_Registry import ClientRegistry
|
||||
from datetime import datetime
|
||||
from typing import Optional, List, Union, AsyncGenerator
|
||||
import re
|
||||
import json
|
||||
|
||||
from entrypoint.init_db import db_credencial
|
||||
from src.Logger.logger_db import LoggerDB, logger
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
LoggerDB(db_credencial, "logger_agentes", created_by="sistema")
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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
|
||||
from domains.Llms.Embedders.Base_Embedder import EmbedderABC # Asegúrate de que EmbedderABC esté en este módulo
|
||||
from domains.ApiKeys.openai_apikey import OpenAICredencial
|
||||
from domains.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
|
||||
class OpenAIEmbedder(EmbedderABC):
|
||||
def __init__(self, credencial: OpenAICredencial,
|
||||
+8
-8
@@ -3,15 +3,15 @@ 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 domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.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
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.base import Base
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Llms.Embedders.Openai_embedder import OpenAIEmbedder
|
||||
from domains.ApiKeys.openai_apikey import OpenAICredencial
|
||||
|
||||
# ----------------------
|
||||
# Cargar configuración desde .env si se requiere
|
||||
@@ -1,4 +1,4 @@
|
||||
from src.Llms.MCPs.McpClient import MCPClient
|
||||
from domains.Llms.MCPs.McpClient import MCPClient
|
||||
from typing import Any
|
||||
|
||||
class ClientRegistry:
|
||||
@@ -1,9 +1,9 @@
|
||||
from sqlalchemy import Table, Column, Integer, String, MetaData, insert, select, delete
|
||||
from typing import Literal
|
||||
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion # Usamos la clase específica
|
||||
from src.Llms.Memory.Base_MemoryConv import MemoryConvABC
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion # Usamos la clase específica
|
||||
from domains.Llms.Memory.Base_MemoryConv import MemoryConvABC
|
||||
|
||||
|
||||
class MemoryConvPostgres(MemoryConvABC):
|
||||
@@ -1,7 +1,7 @@
|
||||
from src.Llms.Modelos.Base_model import ModeloABC
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Llms.Modelos.Base_model import ModeloABC
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
from typing import AsyncGenerator, Union
|
||||
from src.ConexionApis.Ollama_cliente import OllamaCliente # Asegúrate de importar correctamente
|
||||
from domains.ConexionApis.Ollama_cliente import OllamaCliente # Asegúrate de importar correctamente
|
||||
import asyncio
|
||||
|
||||
class ModeloOllama(ModeloABC):
|
||||
@@ -1,6 +1,6 @@
|
||||
from src.Llms.Modelos.Base_model import ModeloABC
|
||||
from src.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Llms.Modelos.Base_model import ModeloABC
|
||||
from domains.ConexionApis.OpenAi_conexion import OpenAICliente
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
import asyncio
|
||||
from typing import AsyncGenerator, Union
|
||||
|
||||
@@ -2,15 +2,15 @@ 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 domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.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
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.base import Base
|
||||
from domains.Llms.Modelos.Openai_model import ModeloOpenAI # Clase real de lógica
|
||||
|
||||
# ----------------------
|
||||
# Cargar clave maestra
|
||||
@@ -3,9 +3,9 @@ from sqlalchemy import Column, Integer, String, Text, TIMESTAMP
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from src.ArquitectureLayer.Model import Model_base
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial
|
||||
|
||||
class LoggerDB:
|
||||
_sink_removido = False # ← evita múltiples remove() si se crean varias instancias
|
||||
@@ -1,11 +1,11 @@
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from src.Llms.Embedders.Base_Embedder import EmbedderABC # Asegúrate de que esta ruta sea correcta
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Llms.Embedders.Base_Embedder import EmbedderABC # Asegúrate de que esta ruta sea correcta
|
||||
from typing import List, Optional
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from sqlalchemy import MetaData # Asegúrate de importar esto
|
||||
from src.TextManager.notas_mmr import generar_tabla_nota_para_biblioteca # Ajusta si es necesario
|
||||
from domains.TextManager.notas_mmr import generar_tabla_nota_para_biblioteca # Ajusta si es necesario
|
||||
from sqlalchemy import inspect
|
||||
from src.base import Base
|
||||
from domains.base import Base
|
||||
|
||||
|
||||
class Biblioteca:
|
||||
@@ -3,16 +3,16 @@ import base64
|
||||
from dotenv import load_dotenv
|
||||
from sqlalchemy import Column, String, Integer
|
||||
|
||||
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||
from src.ArquitectureLayer.Model import Model_base
|
||||
from src.ArquitectureLayer.Repo import Repo_base
|
||||
from domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ArquitectureLayer.Repo import Repo_base
|
||||
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from src.base import Base
|
||||
from src.Security.Encriptar import Encriptar_fernet
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from src.Llms.Embedders.Base_Embedder import EmbedderABC
|
||||
from src.TextManager.biblioteca import Biblioteca # Suponiendo que defines la clase lógica Biblioteca aquí
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.base import Base
|
||||
from domains.Security.Encriptar import Encriptar_fernet
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Llms.Embedders.Base_Embedder import EmbedderABC
|
||||
from domains.TextManager.biblioteca import Biblioteca # Suponiendo que defines la clase lógica Biblioteca aquí
|
||||
|
||||
# ----------------------
|
||||
# Cargar clave maestra
|
||||
@@ -1,4 +1,4 @@
|
||||
from src.Security.GenerarIDs import GeneradorIDUnico
|
||||
from domains.Security.GenerarIDs import GeneradorIDUnico
|
||||
from typing import List
|
||||
|
||||
class Nota:
|
||||
@@ -3,17 +3,17 @@ from dotenv import load_dotenv
|
||||
from sqlalchemy import Table, Column, String, Text, MetaData
|
||||
from pgvector.sqlalchemy import Vector
|
||||
from sqlalchemy.orm import registry, Session
|
||||
from src.TextManager.nota import Nota
|
||||
from src.ConexionSql.Base_conexion import ConexionBase
|
||||
from domains.TextManager.nota import Nota
|
||||
from domains.ConexionSql.Base_conexion import ConexionBase
|
||||
from typing import Tuple
|
||||
import re
|
||||
|
||||
|
||||
from src.ArquitectureLayer.Mapper import Mapper_base
|
||||
from src.ArquitectureLayer.Model import Model_base
|
||||
from src.ArquitectureLayer.Repo import Repo_base
|
||||
from domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ArquitectureLayer.Repo import Repo_base
|
||||
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial # Asegúrate de tener esta clase implementada correctamente
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial # Asegúrate de tener esta clase implementada correctamente
|
||||
|
||||
|
||||
titulo = os.getenv('DB_TITLE')
|
||||
@@ -34,11 +34,11 @@ db_credencial = PostgresCredencial(
|
||||
)
|
||||
|
||||
# from entrypoint.init_db import db_credencial
|
||||
from src.Logger.logger_db import LoggerDB, logger
|
||||
from domains.Logger.logger_db import LoggerDB, logger
|
||||
LoggerDB(db_credencial, "logger_textos", created_by="sistema")
|
||||
|
||||
|
||||
from src.base import Base # Este es tu declarative_base()
|
||||
from domains.base import Base # Este es tu declarative_base()
|
||||
|
||||
# ----------------------
|
||||
# Cargar .env
|
||||
@@ -0,0 +1,15 @@
|
||||
class Usuario:
|
||||
def __init__(self, id: int, nombre: str, email: str, activo: bool = True):
|
||||
self.id = id
|
||||
self.nombre = nombre
|
||||
self.email = email
|
||||
self.activo = activo
|
||||
|
||||
def activar(self):
|
||||
self.activo = True
|
||||
|
||||
def desactivar(self):
|
||||
self.activo = False
|
||||
|
||||
def __repr__(self):
|
||||
return f"Usuario(id={self.id}, nombre='{self.nombre}', email='{self.email}', activo={self.activo})"
|
||||
@@ -0,0 +1,82 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean
|
||||
from domains.ArquitectureLayer.Model import Model_base
|
||||
from domains.ArquitectureLayer.Mapper import Mapper_base
|
||||
from domains.ArquitectureLayer.Repo import Repo_base
|
||||
from domains.Usuario.usuario import Usuario
|
||||
|
||||
# ----------------------
|
||||
# MODELO (SQLAlchemy)
|
||||
# ----------------------
|
||||
|
||||
class UsuarioModel(Model_base):
|
||||
__tablename__ = 'usuarios'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
nombre = Column(String, nullable=False)
|
||||
email = Column(String, unique=True, nullable=False)
|
||||
activo = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
# ----------------------
|
||||
# MAPPER
|
||||
# ----------------------
|
||||
|
||||
class UsuarioMapper(Mapper_base[Usuario, UsuarioModel]):
|
||||
@staticmethod
|
||||
def to_model(obj: Usuario) -> UsuarioModel:
|
||||
return UsuarioModel(
|
||||
id=obj.id,
|
||||
nombre=obj.nombre,
|
||||
email=obj.email,
|
||||
activo=obj.activo
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_model(model: UsuarioModel) -> Usuario:
|
||||
return Usuario(
|
||||
id=model.id,
|
||||
nombre=model.nombre,
|
||||
email=model.email,
|
||||
activo=model.activo
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def to_dict(obj: Usuario) -> dict:
|
||||
return {
|
||||
'id': obj.id,
|
||||
'nombre': obj.nombre,
|
||||
'email': obj.email,
|
||||
'activo': obj.activo
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data: dict) -> Usuario:
|
||||
return Usuario(
|
||||
id=data['id'],
|
||||
nombre=data['nombre'],
|
||||
email=data['email'],
|
||||
activo=data.get('activo', True)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_model_list(models: list[UsuarioModel]) -> list[Usuario]:
|
||||
return [UsuarioMapper.from_model(m) for m in models]
|
||||
|
||||
# ----------------------
|
||||
# REPO
|
||||
# ----------------------
|
||||
|
||||
class UsuarioRepo(Repo_base[UsuarioModel, Usuario]):
|
||||
def __init__(self, session):
|
||||
super().__init__(
|
||||
session=session,
|
||||
modelo=UsuarioModel,
|
||||
mapper=UsuarioMapper
|
||||
)
|
||||
|
||||
def get_by_email(self, email: str) -> Usuario | None:
|
||||
model = (
|
||||
self.session.query(self.Modelo)
|
||||
.filter_by(email=email, sys_deleted_at=None)
|
||||
.first()
|
||||
)
|
||||
return self.Mapper.from_model(model) if model else None
|
||||
@@ -1,14 +1,14 @@
|
||||
# entrypoint/init_db.py
|
||||
|
||||
from src.base import Base
|
||||
from src.ConexionSql.Postgres_conexion import PostgresConexion # Asegúrate de tener esta clase implementada correctamente
|
||||
from src.Credenciales.postgres_credencial import PostgresCredencial # Asegúrate de tener esta clase implementada correctamente
|
||||
from domains.base import Base
|
||||
from domains.ConexionSql.Postgres_conexion import PostgresConexion # Asegúrate de tener esta clase implementada correctamente
|
||||
from domains.Credenciales.postgres_credencial import PostgresCredencial # Asegúrate de tener esta clase implementada correctamente
|
||||
|
||||
from src.Credenciales.postgres_credencial_mmr import PostgresCredencialModel
|
||||
from src.ApiKeys.openai_apikey_mmr import OpenAICredencialModel
|
||||
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 domains.Credenciales.postgres_credencial_mmr import PostgresCredencialModel
|
||||
from domains.ApiKeys.openai_apikey_mmr import OpenAICredencialModel
|
||||
from domains.Llms.Modelos.Openai_model_mmr import ModeloOpenAIConfigModel
|
||||
from domains.Llms.Embedders.Openai_embedder_mmr import OpenAIEmbedderModel
|
||||
from domains.TextManager.biblioteca_mmr import BibliotecaModel
|
||||
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
Generated
+7
-17
@@ -8,12 +8,12 @@
|
||||
"name": "mantine-vite-template",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
||||
"@mantine/core": "^8.0.1",
|
||||
"@mantine/hooks": "^8.0.1",
|
||||
"@mantine/tiptap": "^8.0.1",
|
||||
"@react-three/fiber": "^9.1.2",
|
||||
"@tabler/icons": "^3.31.0",
|
||||
"@tabler/icons-react": "^3.31.0",
|
||||
"@tiptap/react": "^2.12.0",
|
||||
"@tiptap/starter-kit": "^2.12.0",
|
||||
"@uiw/react-markdown-preview": "^5.1.4",
|
||||
@@ -548,6 +548,12 @@
|
||||
"@csstools/css-tokenizer": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@cycjimmy/jsmpeg-player": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-6.1.2.tgz",
|
||||
"integrity": "sha512-U9DBDe5fxHmbwQww9rFxMLNI2Wlg7DhPzI7AVFpq8GehiUP7+NwuMPXpP4zAd52sgkxtOqOeMjgE5g0ZLnQZ0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@dimforge/rapier3d-compat": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
|
||||
@@ -2418,22 +2424,6 @@
|
||||
"url": "https://github.com/sponsors/codecalm"
|
||||
}
|
||||
},
|
||||
"node_modules/@tabler/icons-react": {
|
||||
"version": "3.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.31.0.tgz",
|
||||
"integrity": "sha512-2rrCM5y/VnaVKnORpDdAua9SEGuJKVqPtWxeQ/vUVsgaUx30LDgBZph7/lterXxDY1IKR6NO//HDhWiifXTi3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tabler/icons": "3.31.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/codecalm"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
"storybook:build": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cycjimmy/jsmpeg-player": "^6.1.2",
|
||||
"@mantine/core": "^8.0.1",
|
||||
"@mantine/hooks": "^8.0.1",
|
||||
"@mantine/tiptap": "^8.0.1",
|
||||
"@react-three/fiber": "^9.1.2",
|
||||
"@tabler/icons": "^3.31.0",
|
||||
"@tabler/icons-react": "^3.31.0",
|
||||
"@tiptap/react": "^2.12.0",
|
||||
"@tiptap/starter-kit": "^2.12.0",
|
||||
"@uiw/react-markdown-preview": "^5.1.4",
|
||||
|
||||
+30
-13
@@ -1,13 +1,14 @@
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
import { HomePage } from './pages/Home.page';
|
||||
import { Consulta_API } from './pages/Consulta_api';
|
||||
import { Error_404 } from './pages/404'; // Ajusta si está en otra carpeta
|
||||
import { Grid_Dashboard } from './pages/Grid_dashboard'; // Ajusta si está en otra carpeta
|
||||
import { Biblioteca } from './pages/Biblioteca';
|
||||
import { VisualizacionesRandom } from './pages/Visualizaciones_Random';
|
||||
import { Camara_noir } from './pages/Camaras_noir';
|
||||
import EditorTest from "./pages/Editor_Test"
|
||||
|
||||
import { HomePage } from './frontend_domains/Home/Home.page';
|
||||
import { Consulta_API } from './frontend_domains/Experiments/Consulta_api';
|
||||
import { Error_404 } from './frontend_domains/FitzStudio/404/404'; // Ajusta si está en otra carpeta
|
||||
import { Grid_Dashboard } from './frontend_domains/Experiments/Grid_dashboard'; // Ajusta si está en otra carpeta
|
||||
import { Biblioteca } from './frontend_domains/TextEditor/Biblioteca';
|
||||
import { VisualizacionesRandom } from './frontend_domains/Experiments/Visualizaciones_Random';
|
||||
import { Camara_noir } from './frontend_domains/CamaraNoir/Camaras_noir';
|
||||
import EditorTest from "./frontend_domains/TextEditor/Editor_Test";
|
||||
import { ChatPage } from './frontend_domains/Llms/Chat/ChatPage';
|
||||
import { LoginPage } from './frontend_domains/Usuarios/Login.page';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
|
||||
@@ -21,19 +22,29 @@ const router = createBrowserRouter([
|
||||
|
||||
|
||||
|
||||
// LLMs
|
||||
// Biblioteca
|
||||
|
||||
{
|
||||
path: '/llms/Biblioteca',
|
||||
path: '/bibliot/Biblioteca',
|
||||
element: <Biblioteca />,
|
||||
},
|
||||
{
|
||||
path: '/llms/editortest',
|
||||
path: '/bibliot/editortest',
|
||||
element: <EditorTest />,
|
||||
},
|
||||
|
||||
|
||||
// Camara
|
||||
|
||||
// Chat LLM
|
||||
|
||||
{
|
||||
path: '/llms/chat',
|
||||
element: <ChatPage />,
|
||||
},
|
||||
|
||||
|
||||
|
||||
// CamaraNoir
|
||||
|
||||
{
|
||||
path: '/camara/principal',
|
||||
@@ -59,8 +70,14 @@ const router = createBrowserRouter([
|
||||
},
|
||||
|
||||
|
||||
// Login
|
||||
{
|
||||
path: '/login',
|
||||
element: <LoginPage />,
|
||||
},
|
||||
|
||||
|
||||
// FitzStudio Pages -------------------------------------------------------
|
||||
// Error 404
|
||||
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// https://tabler.io/icons
|
||||
|
||||
// OUTLINED
|
||||
export { default as IconArrowLeft } from './outlined/arrow-left.svg?react';
|
||||
export { default as IconHomeOutline } from './outlined/home.svg?react';
|
||||
@@ -14,6 +16,7 @@ export { default as IconCheck } from './outlined/check.svg?react';
|
||||
export { default as CameraPlus } from './outlined/camera-plus.svg?react';
|
||||
export { default as Flask } from './outlined/flask.svg?react';
|
||||
export { default as Users } from './outlined/users.svg?react';
|
||||
export { default as IconNotebook } from './outlined/notebook.svg?react';
|
||||
|
||||
// FILLED
|
||||
export { default as IconHomeFilled } from './filled/home.svg?react';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Archivo: components/CanvasDisplay.tsx
|
||||
import { Box } from '@mantine/core';
|
||||
import { RefObject } from 'react';
|
||||
|
||||
interface CanvasDisplayProps {
|
||||
canvasRef: RefObject<HTMLCanvasElement>;
|
||||
}
|
||||
|
||||
export function CanvasDisplay({ canvasRef }: CanvasDisplayProps) {
|
||||
return (
|
||||
<Box style={{ position: 'relative', width: '100%', height: 480 }}>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={640}
|
||||
height={480}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'contain',
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#000',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
// Archivo: components/CaptureGrid.tsx
|
||||
import { useCallback } from 'react';
|
||||
import { SimpleGrid } from '@mantine/core';
|
||||
import { FrameCard } from './FrameCard';
|
||||
|
||||
interface CaptureGridProps {
|
||||
totalSlots: number;
|
||||
capturas: string[][];
|
||||
setCapturas: (value: string[][]) => void;
|
||||
frameIndices: number[];
|
||||
setFrameIndices: (value: number[]) => void;
|
||||
fijados: boolean[];
|
||||
setFijados: (value: boolean[]) => void;
|
||||
frameTemporal: number | null;
|
||||
onScroll: (e: React.WheelEvent, index: number) => void;
|
||||
onSliderChange: (val: number) => void;
|
||||
onSliderEnd: (index: number, val: number) => void;
|
||||
numColumnas: number;
|
||||
}
|
||||
|
||||
export function CaptureGrid({
|
||||
totalSlots,
|
||||
capturas,
|
||||
setCapturas,
|
||||
frameIndices,
|
||||
setFrameIndices,
|
||||
fijados,
|
||||
setFijados,
|
||||
frameTemporal,
|
||||
onScroll,
|
||||
onSliderChange,
|
||||
onSliderEnd,
|
||||
numColumnas,
|
||||
}: CaptureGridProps) {
|
||||
const handleImageClick = useCallback((index: number, dataUrl: string) => {
|
||||
const nuevasCapturas = [...capturas];
|
||||
nuevasCapturas[index] = [dataUrl];
|
||||
setCapturas(nuevasCapturas);
|
||||
|
||||
const nuevosFijados = [...fijados];
|
||||
nuevosFijados[index] = true;
|
||||
setFijados(nuevosFijados);
|
||||
|
||||
const nuevosIndices = [...frameIndices];
|
||||
nuevosIndices[index] = 0;
|
||||
setFrameIndices(nuevosIndices);
|
||||
}, [capturas, fijados, frameIndices, setCapturas, setFijados, setFrameIndices]);
|
||||
|
||||
return (
|
||||
<SimpleGrid cols={numColumnas} style={{ flex: 1, columnGap: 12, rowGap: 4 }}>
|
||||
{Array.from({ length: totalSlots }).map((_, i) => {
|
||||
const frames = capturas[i] ?? [];
|
||||
const currentIndex =
|
||||
!fijados[i] && frameTemporal !== null && frames.length > 0
|
||||
? Math.max(0, Math.min(frames.length - 1, frameTemporal))
|
||||
: frameIndices[i];
|
||||
|
||||
return (
|
||||
<FrameCard
|
||||
key={i}
|
||||
index={i}
|
||||
frames={frames}
|
||||
currentIndex={currentIndex}
|
||||
fijado={fijados[i]}
|
||||
onScroll={onScroll}
|
||||
onSliderChange={onSliderChange}
|
||||
onSliderEnd={onSliderEnd}
|
||||
onImageClick={handleImageClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Archivo: components/ControlPanel.tsx
|
||||
import { Button, Group } from '@mantine/core';
|
||||
|
||||
interface ControlPanelProps {
|
||||
grabando: boolean;
|
||||
onAlternar: () => void;
|
||||
onLimpiar: () => void;
|
||||
onDesfijar: () => void;
|
||||
}
|
||||
|
||||
export function ControlPanel({ grabando, onAlternar, onLimpiar, onDesfijar }: ControlPanelProps) {
|
||||
return (
|
||||
<Group gap="sm">
|
||||
<Button onClick={onAlternar} variant="light" color={grabando ? 'orange' : 'blue'}>
|
||||
{grabando ? 'Grabando... (Presiona Espacio)' : 'Iniciar grabación'}
|
||||
</Button>
|
||||
<Button onClick={onLimpiar} variant="filled" color="red">
|
||||
Eliminar imágenes
|
||||
</Button>
|
||||
<Button onClick={onDesfijar} variant="default" color="gray">
|
||||
Desfijar todos (D)
|
||||
</Button>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Archivo: components/FrameCard.tsx
|
||||
import { Box, HoverCard, Image, Slider, Stack, Text } from '@mantine/core';
|
||||
|
||||
interface FrameCardProps {
|
||||
index: number;
|
||||
frames: string[];
|
||||
currentIndex: number;
|
||||
fijado: boolean;
|
||||
onScroll: (e: React.WheelEvent, index: number) => void;
|
||||
onSliderChange: (val: number) => void;
|
||||
onSliderEnd: (index: number, val: number) => void;
|
||||
onImageClick?: (index: number, dataUrl: string) => void;
|
||||
}
|
||||
|
||||
export function FrameCard({
|
||||
index,
|
||||
frames,
|
||||
currentIndex,
|
||||
fijado,
|
||||
onScroll,
|
||||
onSliderChange,
|
||||
onSliderEnd,
|
||||
onImageClick,
|
||||
}: FrameCardProps) {
|
||||
const borderColor = fijado ? '#4caf50' : '#ccc';
|
||||
|
||||
return (
|
||||
<HoverCard key={index} width={700} shadow="md" position="top" withArrow>
|
||||
<HoverCard.Target>
|
||||
<Box
|
||||
style={{
|
||||
width: 160,
|
||||
height: 120,
|
||||
borderRadius: 8,
|
||||
border: `2px solid ${borderColor}`,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
background: '#f1f1f1',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
{frames.length > 0 && currentIndex < frames.length && (
|
||||
<>
|
||||
<Image
|
||||
src={frames[currentIndex]}
|
||||
alt={`Captura ${index}`}
|
||||
width="100%"
|
||||
height="100%"
|
||||
fit="cover"
|
||||
/>
|
||||
<Text
|
||||
size="xs"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: 4,
|
||||
right: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||
color: 'white',
|
||||
borderRadius: 4,
|
||||
padding: '2px 4px',
|
||||
fontSize: 10,
|
||||
}}
|
||||
>
|
||||
{currentIndex + 1} / {frames.length}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</HoverCard.Target>
|
||||
|
||||
<HoverCard.Dropdown p="xs" onWheel={(e) => onScroll(e, index)}>
|
||||
{frames.length > 0 && currentIndex < frames.length && (
|
||||
<Stack gap={6}>
|
||||
<Image
|
||||
src={frames[currentIndex]}
|
||||
alt={`Vista ampliada ${index}`}
|
||||
style={{ width: '100%', height: 'auto', maxWidth: '100%', cursor: 'zoom-in' }}
|
||||
fit="contain"
|
||||
onClick={async (e) => {
|
||||
const imgElement = e.currentTarget;
|
||||
const img = document.createElement('img');
|
||||
img.src = frames[currentIndex];
|
||||
await img.decode();
|
||||
|
||||
const rect = imgElement.getBoundingClientRect();
|
||||
const clickX = e.clientX - rect.left;
|
||||
const clickY = e.clientY - rect.top;
|
||||
const ratioX = clickX / rect.width;
|
||||
const ratioY = clickY / rect.height;
|
||||
|
||||
const zoomFactor = 2;
|
||||
const cropWidth = img.width / zoomFactor;
|
||||
const cropHeight = img.height / zoomFactor;
|
||||
|
||||
const centerX = img.width * ratioX;
|
||||
const centerY = img.height * ratioY;
|
||||
|
||||
const x = Math.max(0, Math.min(img.width - cropWidth, centerX - cropWidth / 2));
|
||||
const y = Math.max(0, Math.min(img.height - cropHeight, centerY - cropHeight / 2));
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = cropWidth;
|
||||
canvas.height = cropHeight;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
ctx.drawImage(img, x, y, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
|
||||
const dataUrl = canvas.toDataURL('image/jpeg');
|
||||
onImageClick?.(index, dataUrl);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Slider
|
||||
value={currentIndex}
|
||||
onChange={(val) => onSliderChange(val)}
|
||||
onChangeEnd={(val) => onSliderEnd(index, val)}
|
||||
min={0}
|
||||
max={frames.length - 1}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</HoverCard.Dropdown>
|
||||
</HoverCard>
|
||||
);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Archivo: components/GridConfigPanel.tsx
|
||||
import { NumberInput, Stack, Text } from '@mantine/core';
|
||||
|
||||
interface GridConfigPanelProps {
|
||||
numFilas: number;
|
||||
setNumFilas: (val: number) => void;
|
||||
numColumnas: number;
|
||||
setNumColumnas: (val: number) => void;
|
||||
}
|
||||
|
||||
export function GridConfigPanel({ numFilas, setNumFilas, numColumnas, setNumColumnas }: GridConfigPanelProps) {
|
||||
return (
|
||||
<Stack align="center" gap="xs" ml="md">
|
||||
<Text size="sm">Cartas</Text>
|
||||
<NumberInput
|
||||
value={numFilas}
|
||||
onChange={(val) => setNumFilas(Number(val))}
|
||||
min={1}
|
||||
max={5}
|
||||
step={1}
|
||||
size="xs"
|
||||
style={{ width: 60 }}
|
||||
/>
|
||||
<Text size="sm">Jugadores</Text>
|
||||
<NumberInput
|
||||
value={numColumnas}
|
||||
onChange={(val) => setNumColumnas(Number(val))}
|
||||
min={1}
|
||||
max={11}
|
||||
step={1}
|
||||
size="xs"
|
||||
style={{ width: 60 }}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export * from './CanvasDisplay';
|
||||
export * from './ControlPanel';
|
||||
export * from './GridConfigPanel';
|
||||
export * from './CaptureGrid';
|
||||
export * from './FrameCard';
|
||||
export * from './useCamaraNoir';
|
||||
@@ -1,212 +0,0 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export function useCamaraNoir() {
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const bufferPrevioRef = useRef<string[]>([]);
|
||||
const bufferGrabacionRef = useRef<string[]>([]);
|
||||
const bufferAcumuladoRef = useRef<string[]>([]);
|
||||
const pregrabacionActivaRef = useRef(true);
|
||||
const primeraGrabacionRealizadaRef = useRef(false);
|
||||
|
||||
const [bufferGlobal, setBufferGlobal] = useState<string[]>([]);
|
||||
const [intervaloId, setIntervaloId] = useState<ReturnType<typeof setInterval> | null>(null);
|
||||
const [grabando, setGrabando] = useState(false);
|
||||
|
||||
const [capturas, setCapturas] = useState<string[][]>([]);
|
||||
const [frameIndices, setFrameIndices] = useState<number[]>([]);
|
||||
const [fijados, setFijados] = useState<boolean[]>([]);
|
||||
const [frameTemporal, setFrameTemporal] = useState<number | null>(null);
|
||||
|
||||
const [numFilas, setNumFilas] = useState(2);
|
||||
const [numColumnas, setNumColumnas] = useState(10);
|
||||
|
||||
const DELAY_ENTRE_FRAMES_MS = 10;
|
||||
const SEGUNDOS_PRE_GRABACION = 5;
|
||||
const FPS = 1000 / DELAY_ENTRE_FRAMES_MS;
|
||||
const FRAMES_PRE_GRABACION = Math.floor(FPS * SEGUNDOS_PRE_GRABACION);
|
||||
const totalSlots = numFilas * numColumnas;
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
if (!pregrabacionActivaRef.current) return;
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const frame = canvas.toDataURL('image/jpeg');
|
||||
bufferPrevioRef.current.push(frame);
|
||||
if (bufferPrevioRef.current.length > FRAMES_PRE_GRABACION) {
|
||||
bufferPrevioRef.current.shift();
|
||||
}
|
||||
}, DELAY_ENTRE_FRAMES_MS);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const desfijarTodos = () => {
|
||||
setFijados(Array(totalSlots).fill(false));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const socket = new WebSocket('ws://10.8.0.9:8000/ws');
|
||||
socket.binaryType = 'blob';
|
||||
|
||||
socket.onmessage = async (event) => {
|
||||
if (event.data instanceof Blob) {
|
||||
const imgBitmap = await createImageBitmap(event.data);
|
||||
ctx.drawImage(imgBitmap, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
};
|
||||
|
||||
socket.onerror = (e) => console.error('WebSocket error:', e);
|
||||
socket.onclose = () => console.warn('WebSocket cerrado');
|
||||
|
||||
return () => socket.close();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.code === 'Space') {
|
||||
event.preventDefault();
|
||||
alternarGrabacion();
|
||||
} else if (event.key.toLowerCase() === 'f') {
|
||||
event.preventDefault();
|
||||
limpiarCapturas();
|
||||
} else if (event.key.toLowerCase() === 'd') {
|
||||
event.preventDefault();
|
||||
desfijarTodos();
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [grabando, bufferGlobal, totalSlots]);
|
||||
|
||||
useEffect(() => {
|
||||
const total = numFilas * numColumnas;
|
||||
const nuevoCapturas = Array(total)
|
||||
.fill(null)
|
||||
.map((_, i) => capturas[i] ?? bufferGlobal);
|
||||
const nuevoIndices = Array(total)
|
||||
.fill(null)
|
||||
.map((_, i) => frameIndices[i] ?? (frameTemporal ?? Math.floor(bufferGlobal.length / 2)));
|
||||
const nuevosFijados = Array(total)
|
||||
.fill(null)
|
||||
.map((_, i) => fijados[i] ?? false);
|
||||
|
||||
setCapturas(nuevoCapturas);
|
||||
setFrameIndices(nuevoIndices);
|
||||
setFijados(nuevosFijados);
|
||||
}, [numFilas, numColumnas]);
|
||||
|
||||
const iniciarGrabacion = () => {
|
||||
if (grabando) return;
|
||||
setGrabando(true);
|
||||
bufferGrabacionRef.current = [];
|
||||
|
||||
if (!primeraGrabacionRealizadaRef.current) {
|
||||
pregrabacionActivaRef.current = false;
|
||||
}
|
||||
|
||||
const id = setInterval(() => {
|
||||
const frame = capturarFrame();
|
||||
if (frame) {
|
||||
bufferGrabacionRef.current.push(frame);
|
||||
}
|
||||
}, DELAY_ENTRE_FRAMES_MS);
|
||||
|
||||
setIntervaloId(id);
|
||||
};
|
||||
|
||||
const capturarFrame = (): string | null => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return null;
|
||||
return canvas.toDataURL('image/jpeg');
|
||||
};
|
||||
|
||||
const detenerGrabacion = () => {
|
||||
if (!grabando) return;
|
||||
setGrabando(false);
|
||||
if (intervaloId) clearInterval(intervaloId);
|
||||
|
||||
const nuevaSesion = primeraGrabacionRealizadaRef.current
|
||||
? [...bufferGrabacionRef.current] // solo frames nuevos
|
||||
: [...bufferPrevioRef.current, ...bufferGrabacionRef.current];
|
||||
|
||||
bufferAcumuladoRef.current.push(...nuevaSesion);
|
||||
primeraGrabacionRealizadaRef.current = true;
|
||||
|
||||
setBufferGlobal([...bufferAcumuladoRef.current]);
|
||||
setCapturas(Array(totalSlots).fill([...bufferAcumuladoRef.current]));
|
||||
const frameInicial = Math.floor(bufferAcumuladoRef.current.length / 2);
|
||||
setFrameIndices(Array(totalSlots).fill(frameInicial));
|
||||
setFijados(Array(totalSlots).fill(false));
|
||||
setFrameTemporal(frameInicial);
|
||||
};
|
||||
|
||||
const alternarGrabacion = () => {
|
||||
grabando ? detenerGrabacion() : iniciarGrabacion();
|
||||
};
|
||||
|
||||
const limpiarCapturas = () => {
|
||||
setCapturas([]);
|
||||
setFrameIndices([]);
|
||||
setFijados([]);
|
||||
setBufferGlobal([]);
|
||||
bufferGrabacionRef.current = [];
|
||||
bufferPrevioRef.current = [];
|
||||
bufferAcumuladoRef.current = [];
|
||||
primeraGrabacionRealizadaRef.current = false;
|
||||
pregrabacionActivaRef.current = true;
|
||||
setFrameTemporal(null);
|
||||
if (intervaloId) clearInterval(intervaloId);
|
||||
setGrabando(false);
|
||||
};
|
||||
|
||||
const moverFrame = (capturaIndex: number, nuevoIndice: number) => {
|
||||
setFrameIndices((prev) => {
|
||||
const nuevos = [...prev];
|
||||
const max = capturas[capturaIndex]?.length - 1 ?? 0;
|
||||
nuevos[capturaIndex] = Math.max(0, Math.min(max, nuevoIndice));
|
||||
return nuevos;
|
||||
});
|
||||
};
|
||||
|
||||
const moverFrameYFijar = (capturaIndex: number, nuevoIndice: number) => {
|
||||
moverFrame(capturaIndex, nuevoIndice);
|
||||
setFijados((prev) => {
|
||||
const actualizados = [...prev];
|
||||
actualizados[capturaIndex] = true;
|
||||
return actualizados;
|
||||
});
|
||||
setFrameTemporal(nuevoIndice);
|
||||
};
|
||||
|
||||
const manejarScrollEnSlider = (e: React.WheelEvent, index: number) => {
|
||||
e.preventDefault();
|
||||
if (!fijados[index]) return;
|
||||
moverFrame(index, frameIndices[index] + (e.deltaY > 0 ? 1 : -1));
|
||||
};
|
||||
|
||||
return {
|
||||
canvasRef,
|
||||
bufferGlobal,
|
||||
grabando,
|
||||
capturas,
|
||||
frameIndices,
|
||||
fijados,
|
||||
frameTemporal,
|
||||
numFilas,
|
||||
setNumFilas,
|
||||
numColumnas,
|
||||
setNumColumnas,
|
||||
alternarGrabacion,
|
||||
limpiarCapturas,
|
||||
desfijarTodos,
|
||||
manejarScrollEnSlider,
|
||||
moverFrameYFijar,
|
||||
setFrameTemporal,
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
IconDeviceDesktopAnalytics,
|
||||
IconFingerprint,
|
||||
IconGauge,
|
||||
IconNotebook,
|
||||
IconHome2,
|
||||
IconSettings,
|
||||
IconUserOutline as IconUser,
|
||||
@@ -14,8 +15,9 @@ import {
|
||||
|
||||
export const mainLinksdata = [
|
||||
{ icon: IconHome2, label: 'Home' },
|
||||
{ icon: IconNotebook, label: 'Biblioteca' },
|
||||
{ icon: Users, label: 'AgentesLLMs' },
|
||||
{ icon: CameraPlus, label: 'Camera' },
|
||||
{ icon: CameraPlus, label: 'CameraNoir' },
|
||||
{ icon: Flask, label: 'Experimentos' },
|
||||
{ icon: IconSettings, label: 'Settings' },
|
||||
];
|
||||
@@ -1,5 +1,7 @@
|
||||
// src/data/submenuLinks.ts
|
||||
|
||||
import { Biblioteca } from "@/frontend_domains/TextEditor/Biblioteca";
|
||||
|
||||
export const submenuLinks = {
|
||||
|
||||
// Home Principal
|
||||
@@ -9,6 +11,16 @@ export const submenuLinks = {
|
||||
|
||||
],
|
||||
|
||||
// Biblioteca
|
||||
|
||||
Biblioteca: [
|
||||
{ label: 'Biblioteca', to: '/bibliot/Biblioteca' },
|
||||
{ label: 'test', to: '/bibliot/editortest' },
|
||||
|
||||
],
|
||||
|
||||
|
||||
|
||||
// Experimentos
|
||||
Experimentos: [
|
||||
{ label: 'Consulta Api', to: '/experiments/Consulta_API' },
|
||||
@@ -17,8 +29,8 @@ export const submenuLinks = {
|
||||
],
|
||||
|
||||
// Camara
|
||||
Camera: [
|
||||
{ label: 'Camara principal', to: '/camara/principal' },
|
||||
CameraNoir: [
|
||||
{ label: 'Camara_principal', to: '/camara/principal' },
|
||||
],
|
||||
|
||||
// LLms
|
||||
@@ -27,8 +39,7 @@ export const submenuLinks = {
|
||||
{ label: 'LLMs', to: '/llms' },
|
||||
{ label: 'Chat', to: '/llms/chat' },
|
||||
{ label: 'Documentos', to: '/llms/documentos' },
|
||||
{ label: 'Biblioteca', to: '/llms/Biblioteca' },
|
||||
{ label: 'test', to: '/llms/editortest' },
|
||||
|
||||
|
||||
],
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { AppShellWithMenu } from '../FitzStudio/Appshell/Appshell';
|
||||
import { Card, Text, Container } from '@mantine/core';
|
||||
|
||||
export function Camara_noir() {
|
||||
return (
|
||||
<AppShellWithMenu>
|
||||
<Container
|
||||
size="lg"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<Card shadow="sm" padding="xl" radius="md" withBorder>
|
||||
<Text size="lg" mb="md">
|
||||
Cámara Noir en Vivo
|
||||
</Text>
|
||||
<img
|
||||
src="http://10.8.0.9:8000/video"
|
||||
alt="Stream MJPEG en vivo desde Raspberry Pi"
|
||||
style={{
|
||||
width: '640px',
|
||||
height: '480px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #ccc',
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
<Text size="sm" color="dimmed" mt="sm">
|
||||
Transmisión MJPEG en vivo vía FastAPI / libcamera-vid
|
||||
</Text>
|
||||
</Card>
|
||||
</Container>
|
||||
</AppShellWithMenu>
|
||||
);
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
|
||||
import { LlamadorAPI } from '../components/LlamadorAPI';
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import { LlamadorAPI } from './LlamadorAPI';
|
||||
import { AppShellWithMenu } from '../FitzStudio/Appshell/Appshell';
|
||||
|
||||
|
||||
export function Consulta_API() {
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { Grid } from '@mantine/core';
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import { GridDashboard } from '../components/Grid_dashboard';
|
||||
import { AppShellWithMenu } from '../FitzStudio/Appshell/Appshell';
|
||||
import { GridDashboard } from './Grid_dashboard_component';
|
||||
|
||||
export function Grid_Dashboard() {
|
||||
return (
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { Select, Group } from '@mantine/core';
|
||||
import { IconCheck } from '../assets/icons';
|
||||
import { IconCheck } from '../../assets/icons';
|
||||
|
||||
interface MetodoSelectProps {
|
||||
metodo: string;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import { AppShellWithMenu } from '../FitzStudio/Appshell/Appshell';
|
||||
import { Card, Grid, Title, Loader } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Box, Title, Text, Button, Group, Stack, Image, Center } from '@mantine/core';
|
||||
import { useMantineTheme } from '@mantine/core';
|
||||
import { IconArrowLeft } from '../assets/icons';
|
||||
import { IconArrowLeft } from '../../../assets/icons';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { MantineCardWithShader } from '../components/HoloShader'; // Ajusta ruta si es necesario
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import { MantineCardWithShader } from './HoloShader_404'; // Ajusta ruta si es necesario
|
||||
import { AppShellWithMenu } from '../Appshell/Appshell';
|
||||
|
||||
|
||||
|
||||
export function Error_404() {
|
||||
+3
-3
@@ -11,9 +11,9 @@ 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 { 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';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { AppShellWithMenu } from '../components/Appshell/Appshell';
|
||||
import { AppShellWithMenu } from './Appshell/Appshell';
|
||||
|
||||
|
||||
export function Plantilla() {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user