Primer commit

This commit is contained in:
2025-05-05 02:21:55 +02:00
commit 7b6f525809
62 changed files with 78661 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
# Volume mounts
data/postgresql/pgdata/*
pruebas_conceptos/postgres_extensions/pgdata/*
+1
View File
@@ -0,0 +1 @@
3.11
+252
View File
@@ -0,0 +1,252 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "26aa8e2b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Credencial: Credencial_enmanuel\n"
]
}
],
"source": [
"from backend.ApiKeys.openai_apikey import OpenAICredencial\n",
"from backend.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo\n",
"from backend.ConexionSql.Postgres_conexion import PostgresConexion\n",
"\n",
"# 1. Crear instancia de conexión (asegúrate de configurar bien tu conexión en Base_conexion)\n",
"from entrypoint.init_db import db_credencial\n",
"conexion_admin = PostgresConexion(db_credencial)\n",
"\n",
"# 3. Guardar la credencial en la base de datos\n",
"repo = OpenAICredencialRepo(conexion_admin)\n",
"credencial_openai = repo.get_by_id(1)\n",
"print(f\"✅ Credencial: {credencial_openai.titulo}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5b665a6",
"metadata": {},
"outputs": [],
"source": [
"from backend.ConexionApis.OpenAi_conexion import OpenAICliente\n",
"\n",
"cliente = OpenAICliente(credencial_openai)\n",
"\n",
"# system_prompt = \"Eres un asistente útil\"\n",
"# prompt = \"¿Cuálqier pregunta que quieras hacer?\"\n",
"\n",
"# # 3. Enviar texto al modelo usando chat (API moderna)\n",
"# respuesta = cliente.chat_completion(\n",
"# model=\"gpt-3.5-turbo\", # o \"gpt-3.5-turbo\"\n",
"# messages=[\n",
"# {\"role\": \"system\", \"content\": f\"{system_prompt}\"},\n",
"# {\"role\": \"user\", \"content\": f\"{prompt}\"}\n",
"# ],\n",
"# temperature=0.3 # Opcional: controla creatividad\n",
"# )\n",
"\n",
"# # 4. Imprimir respuesta\n",
"# contenido = respuesta.choices[0].message.content\n",
"# print(contenido)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ada431b7",
"metadata": {},
"outputs": [],
"source": [
"from llms.Modelos.Openai_model import ModeloOpenAI\n",
"\n",
"modelo = ModeloOpenAI(\n",
" cliente=cliente,\n",
" model=\"gpt-4o\",\n",
" temperature=1,\n",
" top_p=1.0\n",
")\n",
"\n",
"# respuesta = modelo.responder(\n",
"# prompt=\"¿Cuál es la capital de Japón?\",\n",
"# system_prompt=\"Eres un asistente que responde preguntas de forma interesante y creativa.\",\n",
"# )\n",
"\n",
"# print(respuesta)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "059fba92",
"metadata": {},
"outputs": [],
"source": [
"# from llms.Modelos.Openai_model_mmr import ModeloOpenAIConfigRepo\n",
"\n",
"# modelo_config_repo = ModeloOpenAIConfigRepo(conexion=conexion_admin, cliente=cliente)\n",
"# modelo_config_repo.add(modelo)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ce8628d4",
"metadata": {},
"outputs": [],
"source": [
"from llms.Memory.postgres_MemoryConv import MemoryConvPostgres\n",
"\n",
"memoria = MemoryConvPostgres(\n",
" credencial=db_credencial,\n",
" nombre_tabla=\"memoria_conversacion_pruebas\",\n",
" k=10\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "a25bc742",
"metadata": {},
"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": [
"from llms.Agente import AgenteAI\n",
"\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",
" \"tipo_objeto\": \"<clasificación general: planeta, estrella, galaxia, agujero negro, fenómeno cosmológico, etc.>\",\n",
" \"respuesta_resumida\": \"<resumen de máximo 3 líneas de la explicación>\",\n",
" \"respuesta_detallada\": \"<explicación extensa con base científica, observacional y teórica si aplica>\",\n",
" \"contexto_observacional\": \"<si es observable desde la Tierra, en qué condiciones o con qué instrumentos>\",\n",
" \"referencias_relevantes\": [\"<libros, papers, misiones espaciales o catálogos astronómicos relevantes>\"]\n",
"}\n",
"\n",
"agente = AgenteAI(\n",
" modelo=modelo,\n",
" nombre=\"Experto en Astronomía\",\n",
" descripcion=\"Un experto en astronomía que responde preguntas sobre el universo.\",\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=\"astronomo\",\n",
" memoria=memoria,\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",
"respuesta = agente.interactuar(\n",
" prompt=\"¿Qué es Betelgeuse y por qué se volvió más tenue en 2019?\",\n",
")\n",
"\n",
"\n",
"print(respuesta)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "5a1de9b1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tu nombre es: Experto en Astronomía\n",
"Tu descripción: Un experto en astronomía que responde preguntas sobre el universo.\n",
"Tu Rol: astronomo\n",
"Tus Objetivos: Responder preguntas sobre astronomía y astrofísica, Proporcionar explicaciones detalladas y ejemplos numéricos\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",
"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"
]
}
],
"source": [
"print(agente.full_system_prompt)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "07e3b6de",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"¡Hola! Estoy aquí para ayudarte con cualquier pregunta o tarea que tengas. ¿En qué puedo asistirte hoy?\n"
]
}
],
"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)"
]
}
],
"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
}
+143
View File
@@ -0,0 +1,143 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "5206b9c6",
"metadata": {},
"outputs": [],
"source": [
"from backend.ConexionSql.Postgres_conexion import PostgresConexion\n",
"from backend.Credenciales.postgres_credencial_mmr import PostgresCredencialRepo\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "63a0b954",
"metadata": {},
"outputs": [],
"source": [
"from entrypoint.init_db import db_credencial\n",
"conexion_admin = PostgresConexion(db_credencial)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0575f424",
"metadata": {},
"outputs": [],
"source": [
"\n",
"repo_cred = PostgresCredencialRepo(conexion_admin)\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "a5266309",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"repo_cred.add(db_credencial)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "670c79b7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Production_Fitz_db\n"
]
}
],
"source": [
"modelo_cred = repo_cred.get_by_id(1)\n",
"\n",
"print(modelo_cred.titulo)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6cf421c7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Estado de conexión: exito\n"
]
}
],
"source": [
"# Conectar con la base de datos utilizando el modelo recuperado\n",
"conexion_db = PostgresConexion(modelo_cred)\n",
"# Verificar estado de conexión\n",
"estado = \"exito\" if conexion_db.probar_conexion() else \"fallo\"\n",
"\n",
"print(f\"Estado de conexión: {estado}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "feba1446",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7Souw9SFD5P5RYpRWuTVvFkY7zlxATcN\n"
]
}
],
"source": [
"print(modelo_cred.password)"
]
}
],
"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
}
+80
View File
@@ -0,0 +1,80 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "34b9df41",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from entrypoint import ENV_PATH\n",
"from dotenv import load_dotenv\n",
"dotenv_path = ENV_PATH\n",
"load_dotenv(dotenv_path)\n",
"pssword = os.getenv('MASTER_PASSWORD')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "01c8db97",
"metadata": {},
"outputs": [],
"source": [
"from security.Encriptar import Encriptar_fernet"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "aecfbf44",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Clave de cifrado: ¤òAíÀÇ®8IgÄËïºÅ2a3duÎ4Ô¯5¦ï¤ç··sôÃmL9xWß\n",
"Encriptado (bytes con salt): b'\\xe5\\xba]\\t\\x7f\\xd6\\xa7Y\\xbe[\\xf7!e\\x97\\xc7\\x12gAAAAABoFQxX5Gc_Tyi7ViKNluwd9K8b1sWoJdlBN6OpMJbcG_vb_ZOlMEtlaCH5fGppSg8eegU8LLST-uSTcHh3BVBWfZO17g2uurbFACsyMp8lEQu3sFs='\n",
"Desencriptado: Hola, mundo secreto\n"
]
}
],
"source": [
"# Definir la clave como texto plano\n",
"print(\"Clave de cifrado:\", pssword)\n",
"\n",
"# Encriptar un mensaje\n",
"mensaje = \"Hola, mundo secreto\"\n",
"cifrado = Encriptar_fernet.encriptar(mensaje, pssword)\n",
"print(\"Encriptado (bytes con salt):\", cifrado)\n",
"\n",
"# Desencriptar el mensaje\n",
"descifrado = Encriptar_fernet.desencriptar(cifrado, pssword)\n",
"print(\"Desencriptado:\", descifrado)"
]
}
],
"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
}
View File
View File
+21
View File
@@ -0,0 +1,21 @@
class OpenAICredencial:
def __init__(self, titulo: str, api_key: str, organizacion: str = None):
"""
:param titulo: Nombre descriptivo para esta credencial.
:param api_key: Clave secreta de la API de OpenAI.
:param organizacion: (Opcional) ID de la organización asociada a la cuenta de OpenAI.
"""
self.titulo = titulo
self.api_key = api_key
self.organizacion = organizacion
def get_headers(self) -> dict:
"""
Retorna los encabezados necesarios para autenticar una petición HTTP a OpenAI.
"""
headers = {
"Authorization": f"Bearer {self.api_key}"
}
if self.organizacion:
headers["OpenAI-Organization"] = self.organizacion
return headers
+92
View File
@@ -0,0 +1,92 @@
import os
import base64
from dotenv import load_dotenv
from sqlalchemy import Column, Integer, String
from backend.ConexionSql.Base_conexion import ConexionBase
from backend.base import Base
from backend.ApiKeys.openai_apikey import OpenAICredencial
from security.Encriptar import Encriptar_fernet
from entrypoint import ENV_PATH
# ----------------------
# Cargar clave maestra
# ----------------------
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 OpenAICredencialModel(Base):
__tablename__ = 'openai_credenciales'
id = Column(Integer, primary_key=True)
titulo = Column(String, nullable=False)
api_key = Column(String, nullable=False) # Encriptada como base64 string
organizacion = Column(String, nullable=True)
# ----------------------
# MAPPER
# ----------------------
class OpenAICredencialMapper:
@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
def from_dict(data: dict) -> OpenAICredencial:
return OpenAICredencial(
titulo=data["titulo"],
api_key=Encriptar_fernet.desencriptar(
base64.b64decode(data["api_key"]), pssword
),
organizacion=data.get("organizacion")
)
@staticmethod
def from_model(model: OpenAICredencialModel) -> OpenAICredencial:
return OpenAICredencial(
titulo=model.titulo,
api_key=Encriptar_fernet.desencriptar(
base64.b64decode(model.api_key), pssword
),
organizacion=model.organizacion
)
# ----------------------
# REPO
# ----------------------
class OpenAICredencialRepo:
def __init__(self, conexion: ConexionBase):
self.session = conexion.get_session()
def add(self, credencial: OpenAICredencial) -> int:
data = OpenAICredencialMapper.to_dict(credencial)
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:
model = self.session.query(OpenAICredencialModel).filter_by(titulo=titulo).first()
return OpenAICredencialMapper.from_model(model) if model else None
def get_by_id(self, id_: int) -> OpenAICredencial | None:
model = self.session.get(OpenAICredencialModel, id_)
return OpenAICredencialMapper.from_model(model) if model else None
+59
View File
@@ -0,0 +1,59 @@
from openai import OpenAI
from backend.ApiKeys.openai_apikey import OpenAICredencial
class OpenAICliente:
def __init__(self, credencial: OpenAICredencial):
"""
Inicializa el cliente de OpenAI con una instancia de OpenAICredencial.
"""
self.credencial = credencial
self.client = OpenAI(api_key=self.credencial.api_key)
if self.credencial.organizacion:
self.client.organization = self.credencial.organizacion
# --- Chat Completions ---
def chat_completion(self, model: str, messages: list, **kwargs):
return self.client.chat.completions.create(model=model, messages=messages, **kwargs)
# --- Text Completions (legacy) ---
def completion(self, model: str, prompt: str, **kwargs):
return self.client.completions.create(model=model, prompt=prompt, **kwargs)
# --- Text Edits ---
def edit(self, model: str, input: str, instruction: str, **kwargs):
return self.client.edits.create(model=model, input=input, instruction=instruction, **kwargs)
# --- Embeddings ---
def embedding(self, model: str, input: str | list[str], **kwargs):
return self.client.embeddings.create(model=model, input=input, **kwargs)
# --- Moderation ---
def moderation(self, input: str | list[str], model="text-moderation-latest", **kwargs):
return self.client.moderations.create(input=input, model=model, **kwargs)
# --- Image Generation ---
def image_generate(self, prompt: str, **kwargs):
return self.client.images.generate(prompt=prompt, **kwargs)
# --- Audio Transcription ---
def audio_transcribe(self, model: str, file_path: str, **kwargs):
with open(file_path, "rb") as f:
return self.client.audio.transcriptions.create(model=model, file=f, **kwargs)
# --- Audio Translation ---
def audio_translate(self, model: str, file_path: str, **kwargs):
with open(file_path, "rb") as f:
return self.client.audio.translations.create(model=model, file=f, **kwargs)
# --- File Upload ---
def file_upload(self, file_path: str, purpose="fine-tune", **kwargs):
with open(file_path, "rb") as f:
return self.client.files.create(file=f, purpose=purpose, **kwargs)
# --- File List ---
def file_list(self, **kwargs):
return self.client.files.list(**kwargs)
# --- File Delete ---
def file_delete(self, file_id: str, **kwargs):
return self.client.files.delete(file_id=file_id, **kwargs)
View File
+7
View File
@@ -0,0 +1,7 @@
from abc import ABC, abstractmethod
from sqlalchemy.orm import Session
class ConexionBase(ABC):
@abstractmethod
def get_session(self) -> Session:
pass
+45
View File
@@ -0,0 +1,45 @@
from datetime import datetime, timezone
from sqlalchemy import create_engine, text
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker
from backend.ConexionSql.Base_conexion import ConexionBase
from backend.Credenciales.postgres_credencial import PostgresCredencial
class PostgresConexion(ConexionBase):
def __init__(self, *args, **kwargs):
self.estado = "pendiente"
self.timestamp = datetime.now(timezone.utc)
if args and isinstance(args[0], PostgresCredencial):
credencial = args[0]
self.host = credencial.host
self.port = credencial.port
self.dbname = credencial.dbname
self.user = credencial.user
self.password = credencial.password # se guarda la contraseña
uri = credencial.get_uri()
else:
self.user = kwargs.get("user")
self.password = kwargs.get("password") # se guarda la contraseña
self.host = kwargs.get("host")
self.port = kwargs.get("port", 5432)
self.dbname = kwargs.get("db") or kwargs.get("dbname")
uri = f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.dbname}"
self.engine = create_engine(uri)
self.SessionLocal = sessionmaker(bind=self.engine)
def get_session(self):
return self.SessionLocal()
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
View File
View File
@@ -0,0 +1,14 @@
class PostgresCredencial:
def __init__(self, titulo: str, host: str, port: int, dbname: str, user: str, password: str):
self.titulo = titulo
self.host = host
self.port = port
self.dbname = dbname
self.user = user
self.password = password
def get_uri(self) -> str:
"""
Retorna una URI de conexión para PostgreSQL.
"""
return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.dbname}"
@@ -0,0 +1,106 @@
import os
from dotenv import load_dotenv
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from backend.ConexionSql.Base_conexion import ConexionBase
from backend.base import Base
from backend.Credenciales.postgres_credencial import PostgresCredencial
from security.Encriptar import Encriptar_fernet
# ----------------------
# 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 PostgresCredencialModel(Base):
__tablename__ = 'postgres_credenciales'
id = Column(Integer, primary_key=True)
titulo = Column(String, nullable=False)
host = Column(String, nullable=False)
port = Column(Integer, nullable=False)
dbname = Column(String, nullable=False)
user = Column(String, nullable=False)
password = Column(String, nullable=False) # Encriptada como base64 string
# ----------------------
# MAPPER
# ----------------------
import base64
class PostgresCredencialMapper:
@staticmethod
def to_dict(obj: PostgresCredencial) -> dict:
return {
"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_dict(data: dict) -> PostgresCredencial:
return PostgresCredencial(
titulo=data["titulo"],
host=data["host"],
port=data["port"],
dbname=data["dbname"],
user=data["user"],
password=Encriptar_fernet.desencriptar(
base64.b64decode(data["password"]), pssword
)
)
@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
# ----------------------
class PostgresCredencialRepo:
def __init__(self, conexion: ConexionBase):
self.session = conexion.get_session()
def add(self, credencial: PostgresCredencial) -> int:
data = PostgresCredencialMapper.to_dict(credencial)
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:
model = self.session.query(PostgresCredencialModel).filter_by(titulo=titulo).first()
return PostgresCredencialMapper.from_model(model) if model else None
def get_by_id(self, id_: int) -> PostgresCredencial | None:
model = self.session.get(PostgresCredencialModel, id_)
return PostgresCredencialMapper.from_model(model) if model else None
View File
+3
View File
@@ -0,0 +1,3 @@
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
+14
View File
@@ -0,0 +1,14 @@
# 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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+97
View File
@@ -0,0 +1,97 @@
E:\Fitz_Studio
├── .git
│ ├── FETCH_HEAD
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── fsmonitor-watchman.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── pre-merge-commit.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ ├── pre-receive.sample
│ │ ├── prepare-commit-msg.sample
│ │ ├── push-to-checkout.sample
│ │ ├── sendemail-validate.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── info
│ │ └── pack
│ └── refs
│ ├── heads
│ └── tags
├── .gitignore
├── .python-version
├── .venv
│ ├── .gitignore
│ ├── .lock
│ ├── CACHEDIR.TAG
│ ├── Lib
│ │ └── site-packages
│ ├── Scripts
│ │ ├── activate
│ │ ├── activate.bat
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── activate.nu
│ │ ├── activate.ps1
│ │ ├── activate_this.py
│ │ ├── deactivate.bat
│ │ ├── dotenv.exe
│ │ ├── pip.exe
│ │ ├── pip3.11.exe
│ │ ├── pip3.exe
│ │ ├── pydoc.bat
│ │ ├── python.exe
│ │ └── pythonw.exe
│ ├── include
│ │ └── site
│ └── pyvenv.cfg
├── README.md
├── backend
│ ├── ConexionSql
│ │ ├── Base_conexion.py
│ │ ├── Postgres_conexion.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── Credenciales
│ │ ├── __init__.py
│ │ ├── postgres_credencial.py
│ │ └── postgres_credencial_mmr.py
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── base.cpython-311.pyc
│ └── base.py
├── config
│ └── .env
├── data
│ ├── files
│ │ └── tree.txt
│ ├── postgresql
│ │ ├── docker-compose.yml
│ │ └── pgdata
│ └── sqlite
├── entrypoint
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-311.pyc
│ │ └── init_db.cpython-311.pyc
│ ├── add_to_pythonpath.ps1
│ └── init_db.py
├── main.py
├── pyproject.toml
└── scripts
├── __init_.py
├── __pycache__
│ └── prueba_carga_postrgesql.cpython-311.pyc
├── datos_para_llms
│ └── generar_tree.py
└── prueba_carga_postrgesql.py
+15
View File
@@ -0,0 +1,15 @@
version: '3.8'
services:
db:
image: postgres:15
container_name: postgres_container
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 7Souw9SFD5P5RYpRWuTVvFkY7zlxATcN
POSTGRES_DB: fitz_db
ports:
- "5432:5432"
volumes:
- ./pgdata:/var/lib/postgresql/data
+14
View File
@@ -0,0 +1,14 @@
import os
from dotenv import load_dotenv
# Calcular ruta absoluta al .env
ENV_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'config', '.env'))
# Cargar el .env si existe
if os.path.exists(ENV_PATH):
load_dotenv(ENV_PATH)
else:
raise FileNotFoundError(f"No se encontró el archivo .env en {ENV_PATH}")
# Exponer la ruta como variable accesible al importar `entrypoint`
__all__ = ['ENV_PATH']
+21
View File
@@ -0,0 +1,21 @@
# Ruta que quieres agregar al PYTHONPATH
$folderPath = "E:\Fitz_Studio"
# Obtener el PYTHONPATH actual del entorno de usuario (si existe)
$currentPythonPath = [Environment]::GetEnvironmentVariable("PYTHONPATH", "User")
# Verificar si la ruta ya está incluida
if ($currentPythonPath -and $currentPythonPath.Split(';') -contains $folderPath) {
Write-Host "La ruta ya está en PYTHONPATH."
} else {
if ($currentPythonPath) {
$newPythonPath = "$folderPath;$currentPythonPath"
} else {
$newPythonPath = "$folderPath"
}
# Establecer el nuevo PYTHONPATH en el entorno del usuario
[Environment]::SetEnvironmentVariable("PYTHONPATH", $newPythonPath, "User")
Write-Host "✅ PYTHONPATH actualizado exitosamente. Nuevo valor:"
Write-Host $newPythonPath
}
+48
View File
@@ -0,0 +1,48 @@
# entrypoint/init_db.py
from backend.base import Base
from backend.ConexionSql.Postgres_conexion import PostgresConexion # Asegúrate de tener esta clase implementada correctamente
from backend.Credenciales.postgres_credencial import PostgresCredencial # Asegúrate de tener esta clase implementada correctamente
from backend.Credenciales.postgres_credencial_mmr import PostgresCredencialModel
from backend.ApiKeys.openai_apikey_mmr import OpenAICredencialModel
from llms.Modelos.Openai_model_mmr import ModeloOpenAIConfigModel
from dotenv import load_dotenv
import os
from entrypoint import ENV_PATH
# Ruta específica al archivo .env
dotenv_path = ENV_PATH
# Cargar el archivo
load_dotenv(dotenv_path)
titulo = os.getenv('DB_TITLE')
usuario = os.getenv('DB_USER')
passwrd = os.getenv('DB_PASSWORD')
host = os.getenv('DB_HOST')
port = os.getenv('DB_PORT')
db_name = os.getenv('DB_NAME')
db_credencial = PostgresCredencial(
titulo=titulo,
user=usuario,
password=passwrd,
host=host,
port=port,
dbname=db_name
)
def init_db():
# Crear engine desde la clase de conexión PostgreSQL
conexion = PostgresConexion(db_credencial)
engine = conexion.engine # Recuperamos el engine directamente
print("Creando tablas...")
Base.metadata.create_all(engine)
print("¡Listo!")
+122
View File
@@ -0,0 +1,122 @@
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])
+65
View File
@@ -0,0 +1,65 @@
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.")
View File
+36
View File
@@ -0,0 +1,36 @@
from abc import ABC, abstractmethod
from typing import Literal
class MemoryConvABC(ABC):
"""
Interfaz abstracta para memorias de conversación multi-turno.
"""
def __init__(self, k: int = 10):
"""
:param k: Número máximo de turnos (pares user/assistant) a retornar.
"""
self.k = k
@abstractmethod
def guardar_turno(self, rol: Literal["user", "assistant"], contenido: str) -> None:
"""
Guarda un mensaje de un turno de conversación.
Se guarda secuencialmente y se asume que el orden es respetado.
"""
pass
@abstractmethod
def cargar_historial_chat(self) -> list[dict]:
"""
Devuelve los últimos `k*2` mensajes como lista de dicts tipo chat:
[{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]
"""
pass
@abstractmethod
def limpiar(self) -> None:
"""
Limpia completamente la memoria.
"""
pass
+52
View File
@@ -0,0 +1,52 @@
from sqlalchemy import Table, Column, Integer, String, MetaData, insert, select, delete
from typing import Literal
from backend.Credenciales.postgres_credencial import PostgresCredencial
from backend.ConexionSql.Postgres_conexion import PostgresConexion # Usamos la clase específica
from llms.Memory.Base_MemoryConv import MemoryConvABC
class MemoryConvPostgres(MemoryConvABC):
def __init__(self, nombre_tabla: str, k: int, credencial: PostgresCredencial):
"""
:param nombre_tabla: Nombre de la tabla en PostgreSQL.
:param k: Número de pares user/assistant a recuperar.
:param credencial: Credencial para conectar a PostgreSQL.
"""
super().__init__(k=k)
self.conexion = PostgresConexion(credencial) # Se instancia directamente con la credencial
self.nombre_tabla = nombre_tabla
self.metadata = MetaData()
self.tabla = Table(
self.nombre_tabla,
self.metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("rol", String, nullable=False),
Column("contenido", String, nullable=False),
)
# Crea la tabla si no existe
self.metadata.create_all(self.conexion.engine)
def guardar_turno(self, rol: Literal["user", "assistant"], contenido: str) -> None:
stmt = insert(self.tabla).values(rol=rol, contenido=contenido)
with self.conexion.get_session() as session:
session.execute(stmt)
session.commit()
def cargar_historial_chat(self) -> list[dict]:
stmt = (
select(self.tabla.c.rol, self.tabla.c.contenido)
.order_by(self.tabla.c.id.desc())
.limit(self.k * 2)
)
with self.conexion.get_session() as session:
result = session.execute(stmt).fetchall()
return [{"role": r.rol, "content": r.contenido} for r in reversed(result)]
def limpiar(self) -> None:
stmt = delete(self.tabla)
with self.conexion.get_session() as session:
session.execute(stmt)
session.commit()
+30
View File
@@ -0,0 +1,30 @@
from abc import ABC, abstractmethod
class ModeloABC(ABC):
"""
Clase base para definir la interfaz de un modelo conversacional.
"""
def __init__(
self,
model: str,
temperature: float = 0.7,
top_p: float = 1.0,
top_k: int = None,
frecuencia_penalizacion: float = 0.0,
num_tokens_maximos: int = 512
):
self.model = model
self.temperature = temperature
self.top_p = top_p
self.top_k = top_k
self.frecuencia_penalizacion = frecuencia_penalizacion
self.num_tokens_maximos = num_tokens_maximos
@abstractmethod
async def responder(self, prompt: str, system_prompt: str = "", **kwargs) -> str:
"""
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.
"""
pass
+64
View File
@@ -0,0 +1,64 @@
from llms.Modelos.Base_model import ModeloABC
from backend.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
+86
View File
@@ -0,0 +1,86 @@
import os
from dotenv import load_dotenv
from sqlalchemy import Column, Integer, String, Float, Boolean
from backend.ConexionSql.Base_conexion import ConexionBase
from backend.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]
View File
View File
+11
View File
@@ -0,0 +1,11 @@
# main.py
from entrypoint.init_db import init_db
def main():
# Aquí puedes colocar lógica adicional de arranque si la tienes
init_db()
if __name__ == "__main__":
main()
+84
View File
@@ -0,0 +1,84 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "a4e3159d",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"import os\n",
"\n",
"# Añadir la carpeta padre al sys.path\n",
"parent_dir = os.path.abspath(os.path.join(os.getcwd(), \"..\"))\n",
"if parent_dir not in sys.path:\n",
" sys.path.insert(0, parent_dir)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f2fe8bab",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MARIA MAR CABRERA OCAMPO\n",
"JOAQUINA RAMIREZ BAGLIETTO\n",
"PILAR LLORCA ESTEBAN\n",
"CELSA RAMOS ESTEVEZ\n",
"JOAQUIN VICENTE GARCIA ALVAREZ\n",
"RAQUEL GARAU RODRIGUEZ\n",
"FRANCISCO BORJA TERUEL ALBIÑANA\n",
"URBANA SERRANO LOPEZ\n",
"TERESA FERNANDEZ CALERO\n",
"GABRIEL SANCHEZ LEON\n",
"DELMIRA CHEN JIMENEZ\n",
"LUIS RAMON PALOMARES MAINZ\n",
"SANTIAGO ANDRES GUTIERREZ MATARIN\n",
"JONATHAN TORRES CASADO\n",
"AHMED CATALAN MUÑOZ\n",
"FRANCISCA BUSTAMANTE ROMERO\n",
"BARBARA SOFIA SANTIAGO ALCARAZ\n",
"NEREA LIN COSTA\n",
"ANTONIA DE MIGUEL LOPEZ\n",
"MARIA AMPARO RIPOLLES BAÑON\n"
]
}
],
"source": [
"from utils.Generar_nombres import GeneradorNombre_Spanish\n",
"\n",
"if __name__ == \"__main__\":\n",
" generador = GeneradorNombre_Spanish()\n",
"\n",
" for _ in range(20):\n",
" print(generador.generar_nombre_completo(sexo= None, edad_aprox=None)) # Puedes dejar sexo=None para aleatorio\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
}
+53
View File
@@ -0,0 +1,53 @@
import asyncio
from backend.ApiKeys.openai_apikey import OpenAICredencial
from backend.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo
from backend.ConexionSql.Postgres_conexion import PostgresConexion
from entrypoint.init_db import db_credencial
from backend.ConexionApis.OpenAi_conexion import OpenAICliente
from llms.Modelos.Openai_model import ModeloOpenAI
from llms.Agente import AgenteAI
async def main():
# 🔌 Conexión
conexion_admin = PostgresConexion(db_credencial)
repo = OpenAICredencialRepo(conexion_admin)
credencial_openai = repo.get_by_id(1)
print(f"✅ Credencial: {credencial_openai.titulo}")
# 🤖 Modelo
cliente = OpenAICliente(credencial_openai)
modelo = ModeloOpenAI(
cliente=cliente,
model="gpt-4o",
temperature=1,
top_p=1.0
)
# 🧠 Agente
agente_con_herramientas = AgenteAI(
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"]
)
print("\n🤖 Agente listo. Escribe 'salir' para terminar.")
# 🔁 Loop de interacción
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)
print(f"🤖 Agente: {respuesta}\n")
if __name__ == "__main__":
import os
if os.name == "nt":
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
asyncio.run(main())
+74
View File
@@ -0,0 +1,74 @@
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())
from backend.ApiKeys.openai_apikey import OpenAICredencial
from backend.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo
from backend.ConexionSql.Postgres_conexion import PostgresConexion
# 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 backend.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(
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)
@@ -0,0 +1,42 @@
import asyncio
from multiprocessing import Process
from datetime import datetime
import time
import os
def log(msg):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
def tarea_pesada_cpu():
pid = os.getpid()
log(f"🔧 Proceso pesado INICIADO (PID: {pid})")
suma = sum(i * i for i in range(10**8)) # Simula carga pesada
log(f"🔧 Proceso pesado TERMINADO. Resultado: {suma} (PID: {pid})")
async def tarea_ligera_async(nombre, segundos):
log(f"{nombre} INICIADA")
await asyncio.sleep(segundos)
log(f"{nombre} TERMINADA")
async def main():
log("🎬 Iniciando tareas")
# Crear y lanzar un proceso en paralelo (cálculo pesado)
proceso = Process(target=tarea_pesada_cpu)
proceso.start()
log(f"🕵️ Proceso pesado lanzado con PID {proceso.pid}. Búscalo en el Administrador de tareas (pestaña Detalles).")
# Mientras tanto, corremos tareas asincrónicas
await asyncio.gather(
tarea_ligera_async("Tarea 1", 1),
tarea_ligera_async("Tarea 2", 2)
)
# Esperar a que el proceso termine
proceso.join()
log("🏁 Todas las tareas finalizadas")
if __name__ == "__main__":
asyncio.run(main())
+21
View File
@@ -0,0 +1,21 @@
import asyncio
async def enviar_mensajes():
reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
while True:
mensaje = input("Escribe un mensaje (o 'salir'): ")
if mensaje.lower() == 'salir':
break
writer.write(mensaje.encode())
await writer.drain()
data = await reader.read(100)
print(f"💬 Respuesta del servidor: {data.decode()}")
print("🔚 Cerrando conexión")
writer.close()
await writer.wait_closed()
asyncio.run(enviar_mensajes())
+37
View File
@@ -0,0 +1,37 @@
import asyncio
from datetime import datetime
def log(msg):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
async def tarea_asincrona():
log("Tarea asincrónica INICIADA")
await asyncio.sleep(5)
log("Tarea asincrónica TERMINADA")
async def tarea_paralela():
log("Tarea paralela INICIADA")
await asyncio.sleep(1)
log("Tarea paralela TERMINADA")
async def main():
log("Iniciando flujo principal")
# Lanzar tarea paralela (no bloquea)
asyncio.create_task(tarea_paralela())
# Lanzar tarea asincrónica, pero NO esperarla aún
tarea = asyncio.create_task(tarea_asincrona())
# Hacer otras cosas mientras tanto
log("Realizando acción 1 mientras tareas corren...")
await asyncio.sleep(1)
log("Realizando acción 2 mientras tareas corren...")
# Ahora sí esperar que tarea_asincrona termine
await tarea
log("Flujo principal FINALIZADO")
# Ejecutar el flujo
asyncio.run(main())
+14
View File
@@ -0,0 +1,14 @@
import asyncio
async def tarea(nombre, segundos):
print(f"{nombre} empieza")
await asyncio.sleep(segundos)
print(f"{nombre} termina después de {segundos} segundos")
async def main():
await asyncio.gather(
tarea("Tarea A", 2),
tarea("Tarea B", 3)
)
asyncio.run(main())
+28
View File
@@ -0,0 +1,28 @@
import asyncio
async def manejar_cliente(reader, writer):
addr = writer.get_extra_info('peername')
print(f"📡 Conexión desde {addr}")
while True:
data = await reader.read(100)
if not data:
print(f"❌ Cliente {addr} desconectado")
break
mensaje = data.decode()
print(f"📨 Mensaje de {addr}: {mensaje}")
writer.write(f"✅ Recibido: {mensaje}".encode())
await writer.drain()
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(manejar_cliente, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f"🚀 Servidor escuchando en {addr}")
async with server:
await server.serve_forever()
asyncio.run(main())
@@ -0,0 +1,183 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "5131a32a",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"import os\n",
"\n",
"# Añadir la carpeta padre al sys.path\n",
"parent_dir = os.path.abspath(os.path.join(os.getcwd(), \"..\"))\n",
"if parent_dir not in sys.path:\n",
" sys.path.insert(0, parent_dir)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0ea2a77c",
"metadata": {},
"outputs": [],
"source": [
"from backend.ApiKeys.openai_apikey import OpenAICredencial\n",
"from backend.ApiKeys.openai_apikey_mmr import OpenAICredencialRepo # Ajusta si está en otro módulo\n",
"from backend.ConexionSql.Postgres_conexion import PostgresConexion\n",
"\n",
"# 1. Crear instancia de conexión (asegúrate de configurar bien tu conexión en Base_conexion)\n",
"from entrypoint.init_db import db_credencial\n",
"conexion_admin = PostgresConexion(db_credencial)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "b3bdf88a",
"metadata": {},
"outputs": [],
"source": [
"from sqlalchemy import text\n",
"\n",
"def crear_tabla_textos(conexion: PostgresConexion):\n",
" sql = text(\"\"\"\n",
" CREATE EXTENSION IF NOT EXISTS vector;\n",
"\n",
" CREATE TABLE IF NOT EXISTS textos (\n",
" id SERIAL PRIMARY KEY,\n",
" contenido TEXT NOT NULL,\n",
" embedding VECTOR(384)\n",
" );\n",
" \n",
" -- Crear índice opcional para mejorar la búsqueda por similitud\n",
" CREATE INDEX IF NOT EXISTS idx_textos_embedding\n",
" ON textos USING ivfflat (embedding vector_cosine_ops)\n",
" WITH (lists = 100);\n",
" \"\"\")\n",
" with conexion.engine.begin() as conn:\n",
" conn.execute(sql)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f2622707",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"e:\\Fitz_Studio\\.venv\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
]
}
],
"source": [
"from sentence_transformers import SentenceTransformer\n",
"\n",
"modelo = SentenceTransformer(\"all-MiniLM-L6-v2\")\n",
"\n",
"def insertar_texto(conexion: PostgresConexion, texto: str):\n",
" embedding = modelo.encode(texto).tolist()\n",
" query = text(\"INSERT INTO textos (contenido, embedding) VALUES (:contenido, :embedding)\")\n",
" \n",
" with conexion.engine.begin() as conn:\n",
" conn.execute(query, {\"contenido\": texto, \"embedding\": embedding})"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "20497f9f",
"metadata": {},
"outputs": [],
"source": [
"def buscar_similares(conexion: PostgresConexion, texto: str, k: int = 5):\n",
" emb = modelo.encode(texto).tolist()\n",
" sql = text(\"\"\"\n",
" SELECT contenido, embedding <#> CAST(:embedding AS vector) AS distancia\n",
" FROM textos\n",
" ORDER BY embedding <#> CAST(:embedding AS vector)\n",
" LIMIT :k\n",
" \"\"\")\n",
" with conexion.engine.connect() as conn:\n",
" resultados = conn.execute(sql, {\"embedding\": emb, \"k\": k}).fetchall()\n",
" for r in resultados:\n",
" print(f\"Texto: {r.contenido} | Distancia coseno: {r.distancia:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "281a9214",
"metadata": {},
"outputs": [],
"source": [
"insertar_texto(conexion_admin, \"El cambio climático representa un reto urgente para la humanidad.\")\n",
"insertar_texto(conexion_admin, \"Las criptomonedas están alterando el panorama financiero global.\")\n",
"insertar_texto(conexion_admin, \"Los algoritmos de recomendación influyen en nuestras decisiones diarias.\")\n",
"insertar_texto(conexion_admin, \"La automatización está reduciendo la necesidad de mano de obra humana.\")\n",
"insertar_texto(conexion_admin, \"El aprendizaje profundo ha mejorado el reconocimiento de voz y de imágenes.\")\n",
"insertar_texto(conexion_admin, \"La inflación está afectando el poder adquisitivo de los consumidores.\")\n",
"insertar_texto(conexion_admin, \"Las energías renovables son clave para un futuro sostenible.\")\n",
"insertar_texto(conexion_admin, \"Las redes sociales impactan en la salud mental de los adolescentes.\")\n",
"insertar_texto(conexion_admin, \"El teletrabajo se ha consolidado como una nueva forma de empleo.\")\n",
"insertar_texto(conexion_admin, \"Los coches autónomos podrían reducir drásticamente los accidentes de tráfico.\")\n",
"insertar_texto(conexion_admin, \"La biotecnología está revolucionando el tratamiento de enfermedades genéticas.\")\n",
"insertar_texto(conexion_admin, \"Los drones están siendo utilizados para entregas y vigilancia.\")\n",
"insertar_texto(conexion_admin, \"Las decisiones económicas de la Reserva Federal impactan los mercados globales.\")\n",
"insertar_texto(conexion_admin, \"El metaverso plantea nuevas oportunidades y desafíos para las empresas tecnológicas.\")\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "ddcf8f49",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Texto: Las criptomonedas están alterando el panorama financiero global. | Distancia coseno: -0.3589\n"
]
}
],
"source": [
"# # 1. Crear la tabla (solo una vez)\n",
"# crear_tabla_textos(conexion_admin)\n",
"\n",
"# # 2. Insertar un texto\n",
"# insertar_texto(conexion_admin, \"La inteligencia artificial está transformando los negocios.\")\n",
"\n",
"# 3. Buscar textos similares\n",
"buscar_similares(conexion_admin, \"Dinero\", k=1)"
]
}
],
"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,181 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "36832aa6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.2.2\n"
]
}
],
"source": [
"import duckdb\n",
"print(duckdb.__version__)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c357d895",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<duckdb.duckdb.DuckDBPyConnection at 0x1cda135ac30>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conn.execute(\"INSTALL vss; LOAD vss;\")\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "4a7a3ffb",
"metadata": {},
"outputs": [
{
"ename": "BinderException",
"evalue": "Binder Error: HNSW indexes can only be created in in-memory databases, or when the configuration option 'hnsw_enable_experimental_persistence' is set to true.",
"output_type": "error",
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mBinderException\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[13]\u001b[39m\u001b[32m, line 38\u001b[39m\n\u001b[32m 35\u001b[39m conn.execute(\u001b[33m\"\u001b[39m\u001b[33mINSERT INTO textos VALUES (?, ?, ?)\u001b[39m\u001b[33m\"\u001b[39m, (i, texto, vector))\n\u001b[32m 37\u001b[39m \u001b[38;5;66;03m# Crear el índice HNSW en la columna embedding\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m38\u001b[39m \u001b[43mconn\u001b[49m\u001b[43m.\u001b[49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mCREATE INDEX vss_idx ON textos USING HNSW (embedding);\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 40\u001b[39m \u001b[38;5;66;03m# Realizar una búsqueda de los 3 textos más similares a una consulta\u001b[39;00m\n\u001b[32m 41\u001b[39m consulta = \u001b[33m\"\u001b[39m\u001b[33minteligencia artificial en Python\u001b[39m\u001b[33m\"\u001b[39m\n",
"\u001b[31mBinderException\u001b[39m: Binder Error: HNSW indexes can only be created in in-memory databases, or when the configuration option 'hnsw_enable_experimental_persistence' is set to true."
]
}
],
"source": [
"import duckdb\n",
"import numpy as np\n",
"from sentence_transformers import SentenceTransformer\n",
"\n",
"# Conectar a la base de datos\n",
"conn = duckdb.connect(\"textos_vss.duckdb\")\n",
"\n",
"# Instalar y cargar la extensión VSS\n",
"conn.execute(\"INSTALL vss;\")\n",
"conn.execute(\"LOAD vss;\")\n",
"\n",
"# Modelo de embeddings\n",
"model = SentenceTransformer(\"all-MiniLM-L6-v2\")\n",
"\n",
"# Crear la tabla con una columna de embeddings de tipo FLOAT[]\n",
"conn.execute(\"\"\"\n",
"CREATE TABLE IF NOT EXISTS textos (\n",
" id INTEGER PRIMARY KEY,\n",
" texto TEXT,\n",
" embedding FLOAT[]\n",
");\n",
"\"\"\")\n",
"\n",
"# Insertar textos y sus embeddings\n",
"extractos = [\n",
" \"El rápido zorro marrón salta sobre el perro perezoso.\",\n",
" \"La inteligencia artificial está revolucionando el mundo.\",\n",
" \"DuckDB permite análisis embebidos rápidos en Python.\",\n",
" \"Los modelos de lenguaje pueden entender consultas humanas.\",\n",
" \"Python es un lenguaje poderoso para ciencia de datos.\"\n",
"]\n",
"\n",
"for i, texto in enumerate(extractos):\n",
" vector = model.encode(texto).astype(np.float32).tolist()\n",
" conn.execute(\"INSERT INTO textos VALUES (?, ?, ?)\", (i, texto, vector))\n",
"\n",
"# Crear el índice HNSW en la columna embedding\n",
"conn.execute(\"CREATE INDEX vss_idx ON textos USING HNSW (embedding);\")\n",
"\n",
"# Realizar una búsqueda de los 3 textos más similares a una consulta\n",
"consulta = \"inteligencia artificial en Python\"\n",
"vector_consulta = model.encode(consulta).astype(np.float32).tolist()\n",
"resultados = conn.execute(\"\"\"\n",
" SELECT id, texto, array_distance(embedding, ?) AS distancia\n",
" FROM textos\n",
" ORDER BY distancia ASC\n",
" LIMIT 3;\n",
"\"\"\", (vector_consulta,)).fetchall()\n",
"\n",
"# Mostrar los resultados\n",
"for id_, texto, distancia in resultados:\n",
" print(f\"[ID: {id_}] Distancia: {distancia:.4f} → {texto}\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "2f6059bd",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<duckdb.duckdb.DuckDBPyConnection at 0x1cda32d9730>"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conn = duckdb.connect(\"textos_vss.duckdb\")\n",
"conn.execute(\"SET hnsw_enable_experimental_persistence=true;\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "449bebc1",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<duckdb.duckdb.DuckDBPyConnection at 0x1cda322a5b0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conn.execute(\"DELETE FROM textos;\")\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
}
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
FROM postgres:16
ENV DEBIAN_FRONTEND=noninteractive
# Instala dependencias necesarias para compilar extensiones
RUN apt-get update && apt-get install -y \
build-essential \
git \
wget \
curl \
ca-certificates \
postgresql-server-dev-16 \
cmake \
pkg-config \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
# Instala pgvector
RUN git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git && \
cd pgvector && make && make install && \
cd .. && rm -rf pgvector
# Instala TimescaleDB
# Clona y compila TimescaleDB
RUN git clone --branch 2.14.2 https://github.com/timescale/timescaledb.git && \
cd timescaledb && \
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DREGRESS_CHECKS=OFF .. && \
make && make install && \
cd ../.. && rm -rf timescaledb
# Copia script de inicialización
COPY ./init.sql /docker-entrypoint-initdb.d/init.sql
@@ -0,0 +1,438 @@
--
-- PostgreSQL database cluster dump
--
SET default_transaction_read_only = off;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
--
-- Roles
--
CREATE ROLE postgres;
ALTER ROLE postgres WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION BYPASSRLS PASSWORD 'SCRAM-SHA-256$4096:qnEt3ZsN8+BkkNaJ9LBBGg==$qXhcNOlxFgwZojkJ84U0Tqt0KiqyBgTNrIirnI1aM3o=:d5YPrrbXlUPaF7ionv/spbLgmUrwyRwV+5y2a3Qpb34=';
--
-- User Configurations
--
--
-- Databases
--
--
-- Database "template1" dump
--
\connect template1
--
-- PostgreSQL database dump
--
-- Dumped from database version 15.12 (Debian 15.12-1.pgdg120+1)
-- Dumped by pg_dump version 15.12 (Debian 15.12-1.pgdg120+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- PostgreSQL database dump complete
--
--
-- Database "fitz_db" dump
--
--
-- PostgreSQL database dump
--
-- Dumped from database version 15.12 (Debian 15.12-1.pgdg120+1)
-- Dumped by pg_dump version 15.12 (Debian 15.12-1.pgdg120+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: fitz_db; Type: DATABASE; Schema: -; Owner: postgres
--
CREATE DATABASE fitz_db WITH TEMPLATE = template0 ENCODING = 'UTF8' LOCALE_PROVIDER = libc LOCALE = 'en_US.utf8';
ALTER DATABASE fitz_db OWNER TO postgres;
\connect fitz_db
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: memoria_conversacion_pruebas; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.memoria_conversacion_pruebas (
id integer NOT NULL,
rol character varying NOT NULL,
contenido character varying NOT NULL
);
ALTER TABLE public.memoria_conversacion_pruebas OWNER TO postgres;
--
-- Name: memoria_conversacion_pruebas_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE public.memoria_conversacion_pruebas_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.memoria_conversacion_pruebas_id_seq OWNER TO postgres;
--
-- Name: memoria_conversacion_pruebas_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
ALTER SEQUENCE public.memoria_conversacion_pruebas_id_seq OWNED BY public.memoria_conversacion_pruebas.id;
--
-- Name: modelo_openai_configs; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.modelo_openai_configs (
id integer NOT NULL,
model character varying NOT NULL,
temperature double precision,
top_p double precision,
top_k integer,
frecuencia_penalizacion double precision,
num_tokens_maximos integer,
use_legacy boolean
);
ALTER TABLE public.modelo_openai_configs OWNER TO postgres;
--
-- Name: modelo_openai_configs_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE public.modelo_openai_configs_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.modelo_openai_configs_id_seq OWNER TO postgres;
--
-- Name: modelo_openai_configs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
ALTER SEQUENCE public.modelo_openai_configs_id_seq OWNED BY public.modelo_openai_configs.id;
--
-- Name: openai_credenciales; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.openai_credenciales (
id integer NOT NULL,
titulo character varying NOT NULL,
api_key character varying NOT NULL,
organizacion character varying
);
ALTER TABLE public.openai_credenciales OWNER TO postgres;
--
-- Name: openai_credenciales_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE public.openai_credenciales_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.openai_credenciales_id_seq OWNER TO postgres;
--
-- Name: openai_credenciales_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
ALTER SEQUENCE public.openai_credenciales_id_seq OWNED BY public.openai_credenciales.id;
--
-- Name: postgres_credenciales; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.postgres_credenciales (
id integer NOT NULL,
titulo character varying NOT NULL,
host character varying NOT NULL,
port integer NOT NULL,
dbname character varying NOT NULL,
"user" character varying NOT NULL,
password character varying NOT NULL
);
ALTER TABLE public.postgres_credenciales OWNER TO postgres;
--
-- Name: postgres_credenciales_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE public.postgres_credenciales_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public.postgres_credenciales_id_seq OWNER TO postgres;
--
-- Name: postgres_credenciales_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
ALTER SEQUENCE public.postgres_credenciales_id_seq OWNED BY public.postgres_credenciales.id;
--
-- Name: memoria_conversacion_pruebas id; Type: DEFAULT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.memoria_conversacion_pruebas ALTER COLUMN id SET DEFAULT nextval('public.memoria_conversacion_pruebas_id_seq'::regclass);
--
-- Name: modelo_openai_configs id; Type: DEFAULT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.modelo_openai_configs ALTER COLUMN id SET DEFAULT nextval('public.modelo_openai_configs_id_seq'::regclass);
--
-- Name: openai_credenciales id; Type: DEFAULT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.openai_credenciales ALTER COLUMN id SET DEFAULT nextval('public.openai_credenciales_id_seq'::regclass);
--
-- Name: postgres_credenciales id; Type: DEFAULT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.postgres_credenciales ALTER COLUMN id SET DEFAULT nextval('public.postgres_credenciales_id_seq'::regclass);
--
-- Data for Name: memoria_conversacion_pruebas; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.memoria_conversacion_pruebas (id, rol, contenido) FROM stdin;
1 user Hola estoy triste porque no tengo ordenador y no puedo trabajar.
2 assistant Lo siento mucho por lo que estás pasando. Es comprensible que te sientas triste al no poder trabajar debido a la falta de un ordenador. ¿Hay alguna razón específica por la que no tengas acceso a uno en este momento? ¿Has pensado en posibles soluciones o alternativas que puedan ayudarte a superar esta dificultad? Estoy aquí para escucharte y apoyarte en lo que necesites.
3 user Recuerdas porque me siento triste?
4 assistant Claro, entiendo que te sientes triste porque no tener un ordenador te impide trabajar, lo cual puede generar preocupación y estrés sobre tu situación actual. Es normal sentirse así cuando nos enfrentamos a obstáculos que nos limitan en nuestras tareas diarias. ¿Cómo te gustaría abordar esta situación? ¿Hay alguien en tu entorno en quien puedas pedir prestado un ordenador temporalmente o alguna forma de acceso a recursos que puedan ayudarte a continuar con tu trabajo? Estoy aquí para apoyarte en encontrar posibles soluciones.
5 user Sabes como puedo mejorar mi autoestima?
6 assistant Para mejorar tu autoestima, es importante que empieces por cuidar y valorarte a ti mismo. Aquí te dejo algunas sugerencias que pueden ayudarte:\n\n1. Reconoce tus logros y fortalezas: Haz una lista de tus logros pasados, por pequeños que sean, y recuérdate a ti mismo tus capacidades y cualidades positivas.\n\n2. Practica el autocuidado: Dedica tiempo a actividades que te hagan sentir bien, como el ejercicio, la meditación, la lectura, o cualquier hobby que disfrutes. Cuidar tu bienestar físico y emocional es esencial para fortalecer tu autoestima.\n\n3. Establece límites sanos: Aprende a decir no cuando sea necesario y prioriza tu bienestar emocional. Establecer límites sanos te ayudará a mantener una percepción positiva de ti mismo.\n\n4. Busca apoyo social: Habla con amigos, familiares o profesionales de la salud mental si sientes que necesitas apoyo emocional. Compartir tus pensamientos y sentimientos con personas de confianza puede ser reconfortante.\n\nRecuerda que la autoestima es
7 user Que otras cosas puedo hacer para trabajar?
8 assistant Puedes explorar diferentes opciones para trabajar mientras resuelves la situación con el ordenador. Aquí te dejo algunas sugerencias:\n\n1. Trabajar en proyectos que no requieran un ordenador: Puedes enfocarte en actividades que puedas hacer manualmente, como escribir a mano, dibujar, diseñar o planificar en papel. \n\n2. Visitar una biblioteca o centro comunitario: Muchas bibliotecas suelen contar con ordenadores públicos y acceso a Internet que puedes utilizar de forma gratuita. También puedes investigar si hay algún centro comunitario cercano que ofrezca recursos similares.\n\n3. Explorar opciones de trabajo remoto desde un dispositivo móvil: Dependiendo de tu tipo de trabajo, es posible que puedas realizar tareas básicas o comunicarte con clientes o colegas a través de aplicaciones móviles o plataformas en línea.\n\n4. Buscar oportunidades de trabajo temporales o freelance: Hay plataformas en línea donde puedes encontrar trabajos temporales o proyectos freelance que no requieren un ordenador específico. Esto podría ayudarte a generar ingresos mientras solucionas la falta de ordenador.\n\nRecuerda que es importante
9 user Que otros métodos de terapia conoces?
10 assistant Existen diferentes enfoques y métodos de terapia que pueden ayudar a abordar diferentes problemas emocionales y mejorar el bienestar mental de una persona. Algunos de los métodos de terapia más comunes incluyen:\n\n1. Terapia cognitivo-conductual (TCC): Se centra en identificar y cambiar patrones de pensamiento negativos o destructivos, así como en modificar comportamientos no deseados. Ayuda a las personas a desarrollar habilidades para afrontar mejor sus problemas.\n\n2. Terapia psicodinámica: Se enfoca en explorar los procesos inconscientes que influyen en el pensamiento y el comportamiento de una persona, con el objetivo de aumentar la autoconciencia y comprender mejor las motivaciones detrás de las acciones.\n\n3. Terapia de aceptación y compromiso (ACT): Se basa en aceptar las emociones y pensamientos negativos, mientras se fomenta la acción en línea con los valores personales y objetivos de vida. Promueve la flexibilidad psicológica y el compromiso con un cambio positivo.\n\n4. Terapia interpersonal: Se centra en mejorar las relaciones interpersonales y la comunicación, abordando conflictos y problemas relacionales que puedan contribuir a dificultades emocionales.\n\nEstos son solo algunos ejemplos de enfoques terapéuticos, y es importante encontrar el que mejor se adapte a tus necesidades y preferencias personales. Si estás considerando iniciar terapia, te animo a hablar con un profesional de la salud mental para que juntos puedan explorar las opciones más adecuadas para ti. ¿Hay alguna de estas terapias en particular que te interese o te gustaría conocer más a fondo? Estoy aquí para responder cualquier pregunta que tengas.
11 user Que otros métodos de terapia conoces?
12 assistant Existen diferentes enfoques y métodos de terapia que pueden ayudar a abordar problemas emocionales y promover el bienestar mental. Algunos otros métodos de terapia que podrían ser beneficiosos incluyen:\n\n1. Terapia Gestalt: Se enfoca en aumentar la conciencia de uno mismo y en la integración de los aspectos emocionales, mentales y físicos de la persona. Promueve la responsabilidad personal y la autoexploración.\n\n2. Terapia de EMDR (Desensibilización y Reprocesamiento por Movimientos Oculares): Utiliza movimientos oculares y otros estímulos para ayudar a procesar recuerdos traumáticos y reducir la intensidad emocional asociada a ellos.\n\n3. Terapia de Arte: Incluye diferentes modalidades artísticas como la pintura, la música, la danza o la escritura, para facilitar la expresión emocional y la exploración personal.\n\n4. Terapia Sistémica: Se enfoca en las relaciones interpersonales y el contexto social en el que se desarrollan los problemas, considerando al individuo como parte de un sistema más amplio.\n\nCada método de terapia tiene sus propias características y enfoques, por lo que es recomendable hablar con un profesional de la salud mental para determinar cuál sería el más adecuado para tus necesidades específicas. ¿Te interesa explorar alguno de estos métodos de terapia con más detalle o tienes alguna otra pregunta al respecto? Estoy aquí para brindarte información adicional si lo necesitas.
13 user Que otros métodos de terapia conoces?
14 assistant Me di cuenta de que ya había compartido contigo una lista de métodos de terapia en respuestas anteriores. ¿Hay algo en particular sobre los métodos de terapia que te gustaría explorar más o alguna pregunta específica que quieras hacer al respecto? Estoy aquí para ayudarte en lo que necesites. Sentir curiosidad por diferentes enfoques terapéuticos es positivo y puede ayudarte a encontrar el que mejor se adapte a tus necesidades y preferencias.
15 user Hablame de las estrellas de neutrones y su formación
16 assistant ¡Por supuesto! Las estrellas de neutrones son uno de los objetos más fascinantes en el universo y se forman como resultado de la explosión de supernovas. Permíteme explicarte el proceso de formación de las estrellas de neutrones de una manera detallada:\n\n1. **Explosión de Supernova**: Las estrellas de neutrones se originan a partir de núcleos de estrellas masivas que han agotado su combustible nuclear, lo que desencadena una explosión de supernova. Durante esta explosión, la estrella lanza sus capas externas al espacio y comprime el núcleo restante a densidades extremas.\n\n2. **Colapso Gravitacional**: Tras la explosión de supernova, el núcleo de la estrella colapsa bajo su propia gravedad. Durante este proceso, los electrones y protones se fusionan para formar neutrones a través de la interacción débil, dando lugar a una densidad nuclear extremadamente alta.\n\n3. **Estrella de Neutrones**: La materia comprimida en el núcleo estelar resulta en la formación de una estrella de neutrones. Estas estrellas tienen una densidad increíblemente alta, aproximadamente del orden de 10^14 a 10^15 gramos por centímetro cúbico, lo que hace que una cucharadita de materia de una estrella de neutrones pese tanto como una montaña en la Tierra.\n\n4. **Estabilidad del Equilibrio Gravitacional**: Las estrellas de neutrones son sostenidas por la presión degenerada de los neutrones, que contrarresta la fuerza gravitatoria. Este equilibrio entre la gravedad y la presión degenerada evita que la estrella de neutrones colapse por completo en un agujero negro.\n\n5. **Propiedades Únicas**: Las estrellas de neutrones presentan propiedades fascinantes, como campos magnéticos extremadamente fuertes y rotaciones muy rápidas. Algunas emiten haces de radiación altamente energética, conocidos como pulsares, que son detectados desde la Tierra como pulsos regulares de radiación.\n\nEn resumen, las estrellas de neutrones son remanentes estel
17 user Hablame de las estrellas de neutrones y su formación
18 assistant {\n'objeto_celeste': "Estrella de Neutrones",\n'tipo_objeto': 'Estrella compacta',\n'respuesta_resumida': 'Las estrellas de neutrones se forman a partir de colapsos gravitacionales de núcleos estelares tras explosiones de supernova, alcanzando densidades extremas.',\n'respuesta_detallada': 'Las estrellas de neutrones se originan cuando una estrella masiva agota su combustible nuclear y colapsa bajo su propia gravedad tras una explosión de supernova. Durante este proceso, los electrones y protones se fusionan para formar neutrones, generando una densidad nuclear increíblemente alta. Las estrellas de neutrones tienen una masa de aproximadamente 1.4 veces la del Sol pero un tamaño de unos 20 kilómetros de diámetro, lo que produce densidades del orden de 10^14 a 10^15 gramos por centímetro cúbico. Son sostenidas por la presión degenerada de los neutrones, que equilibra la fuerza gravitatoria, evitando el colapso total en un agujero negro. Presentan propiedades únicas como campos magnéticos intensos y rotaciones veloces, y algunas emiten radiación detectada como pulsos regulares desde la Tierra, conocidas como pulsares.',\n'contexto_observacional': 'Las estrellas de neutrones no son visibles directamente a simple vista debido a su tamaño compacto y distancia en el espacio. Se detectan a través de observaciones de rayos X, radio y ondas gravitacionales en casos de fusiones de estrellas de neutrones.',\n'referencias_relevantes': ['Materia y energía oscura: las estrellas de neutrones y los agujeros negros', 'Supernova nucleosíntesis y evolución de las estrellas masivas']}\n```
19 user ¿Qué es Betelgeuse y por qué se volvió más tenue en 2019?
20 assistant {\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 experimentó un episodio de atenuación en 2019 debido a cambios en su actividad estelar.',\n'respuesta_detallada': 'Betelgeuse es una supergigante roja ubicada en la constelación de Orión, aproximadamente a unos 640 años luz de distancia de la Tierra. En 2019, Betelgeuse experimentó una notable disminución en su brillo, lo que generó interés en la comunidad astronómica y el público en general. La atenuación observada en Betelgeuse se debió probablemente a la combinación de dos factores principales: en primer lugar, la variabilidad intrínseca de Betelgeuse como una supergigante roja inestable, y en segundo lugar, la presencia de manchas estelares en su superficie que bloquearon parcialmente la emisión de luz visible.\n\nEn su etapa evolutiva, Betelgeuse se encuentra en una fase avanzada de su vida, en la que ha agotado gran parte de su combustible nuclear y experimenta pulsaciones radiales en las capas exteriores de la estrella. Estas pulsaciones causan expansiones y contracciones periódicas en el tamaño de Betelgeuse, lo que puede afectar su brillo aparente desde nuestra perspectiva en la Tierra.\n\nAdemás, se cree que la presencia de manchas estelares en la superficie de Betelgeuse durante 2019 contribuyó significativamente a su atenuación. Estas manchas estelares son regiones más frías y opacas en la superficie estelar que pueden bloquear la emisión de luz visible, lo que resulta en una disminución detectable en el brillo de la estrella.\n\nA pesar de esta atenuación temporal, Betelgeuse es conocida por ser una de las estrellas más brillantes y destacadas en el cielo nocturno, y su observación continúa siendo objeto de interés para los astrónomos que estudian la evolución estelar y la actividad de
21 user ¿Qué es Betelgeuse y por qué se volvió más tenue en 2019?
22 assistant {\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 experimentó un episodio de atenuación en 2019 debido a cambios en su actividad estelar.',\n'respuesta_detallada': 'Betelgeuse es una supergigante roja ubicada en la constelación de Orión, aproximadamente a unos 640 años luz de distancia de la Tierra. En 2019, Betelgeuse experimentó una notable disminución en su brillo, lo que generó interés en la comunidad astronómica y el público en general. La atenuación observada en Betelgeuse se debió probablemente a la combinación de dos factores principales: en primer lugar, la variabilidad intrínseca de Betelgeuse como una supergigante roja inestable, y en segundo lugar, la presencia de manchas estelares en su superficie que bloquearon parcialmente la emisión de luz visible.\n\nEn su etapa evolutiva, Betelgeuse se encuentra en una fase avanzada de su vida, en la que ha agotado gran parte de su combustible nuclear y experimenta pulsaciones radiales en las capas exteriores de la estrella. Estas pulsaciones causan expansiones y contracciones periódicas en el tamaño de Betelgeuse, lo que puede afectar su brillo aparente desde nuestra perspectiva en la Tierra.\n\nAdemás, se cree que la presencia de manchas estelares en la superficie de Betelgeuse durante 2019 contribuyó significativamente a su atenuación. Estas manchas estelares son regiones más frías y opacas en la superficie estelar que pueden bloquear la emisió\n'contexto_observacional': 'Betelgeuse es visible a simple vista en el cielo nocturno y forma parte de la constelación de Orión. Su atenuación en 2019 pudo ser observada con telescopios o incluso a simple vista por observadores astronómicos.',\n'referencias_relevantes': ['Evolución estelar de supergigantes rojas', 'Est
\.
--
-- Data for Name: modelo_openai_configs; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.modelo_openai_configs (id, model, temperature, top_p, top_k, frecuencia_penalizacion, num_tokens_maximos, use_legacy) FROM stdin;
1 gpt-3.5-turbo 1 1 \N 0 256 f
\.
--
-- Data for Name: openai_credenciales; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.openai_credenciales (id, titulo, api_key, organizacion) FROM stdin;
1 Credencial_enmanuel IaqxcMlBc2PaXdfOHa+z0mdBQUFBQUJvRlJwUC1kb3ZRdXRpMHBkM3ZsWGM0OGhOOVRrOGp4S3k5bEdWM21sNHNkaWZSU3ZkbWZadHNEZjVURFF0TlBjVnhuVU1aZHV1SzNtenNiT2praFRUMm5WZjFieFJ6emZQejhzRi1FanFuWk8tNVRlYkFaeG1DWlFkX3FwWTA5RjhHSERNQ1lrdWltU2hSOTFiT3pZWE1KcXcxYjhQemlJOXd2M1ZaVHU5TVNxN1NlSkJHSm5uNkVjbElPN0dOYjFaRDh0WEo5MG5kRnpZaWdRVkNSR01ibF84eWF5dXpzT3BOU081ZXJYemlRR2dNR2JwVFl3RlFHcG1Bdy1uVFg1WHFDR3lndkhjWl9BTFBDaGdPejFtbmdlSm41NGN2c0ZNRnVFZGtkdTRpWWlDSkF3PQ== \N
\.
--
-- Data for Name: postgres_credenciales; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.postgres_credenciales (id, titulo, host, port, dbname, "user", password) FROM stdin;
1 Production_Fitz_db localhost 5432 fitz_db postgres VFzrUQ50QKlotGP1WWVKC2dBQUFBQUJvRlJCVUczZ2ZSamxZUy12T3BMTWdHWDU0SVM0bkV0QkVOVjh3T2JXdTcxemZXN2hpMllwOUs0MGF1emNQVzlvTmxEQ2JzbjhtWnhkMVBaWVlUZ0RycTYtaVkxdmEzeW43REFjRzY5X21jSWdMRUdIYUhMUHFZbEtuQzR3N1h4NmhLcks2
\.
--
-- Name: memoria_conversacion_pruebas_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.memoria_conversacion_pruebas_id_seq', 22, true);
--
-- Name: modelo_openai_configs_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.modelo_openai_configs_id_seq', 1, true);
--
-- Name: openai_credenciales_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.openai_credenciales_id_seq', 1, true);
--
-- Name: postgres_credenciales_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('public.postgres_credenciales_id_seq', 1, true);
--
-- Name: memoria_conversacion_pruebas memoria_conversacion_pruebas_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.memoria_conversacion_pruebas
ADD CONSTRAINT memoria_conversacion_pruebas_pkey PRIMARY KEY (id);
--
-- Name: modelo_openai_configs modelo_openai_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.modelo_openai_configs
ADD CONSTRAINT modelo_openai_configs_pkey PRIMARY KEY (id);
--
-- Name: openai_credenciales openai_credenciales_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.openai_credenciales
ADD CONSTRAINT openai_credenciales_pkey PRIMARY KEY (id);
--
-- Name: postgres_credenciales postgres_credenciales_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.postgres_credenciales
ADD CONSTRAINT postgres_credenciales_pkey PRIMARY KEY (id);
--
-- PostgreSQL database dump complete
--
--
-- Database "postgres" dump
--
\connect postgres
--
-- PostgreSQL database dump
--
-- Dumped from database version 15.12 (Debian 15.12-1.pgdg120+1)
-- Dumped by pg_dump version 15.12 (Debian 15.12-1.pgdg120+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- PostgreSQL database dump complete
--
--
-- PostgreSQL database cluster dump complete
--
@@ -0,0 +1,17 @@
version: '3.8'
services:
postgres:
build:
context: .
dockerfile: Dockerfile
container_name: postgres_ext
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 7Souw9SFD5P5RYpRWuTVvFkY7zlxATcN
POSTGRES_DB: fitz_db
ports:
- "5432:5432"
volumes:
- ./pgdata:/var/lib/postgresql/data
restart: always
@@ -0,0 +1,5 @@
-- init.sql
CREATE EXTENSION IF NOT EXISTS timescaledb;
CREATE EXTENSION IF NOT EXISTS pgvector;
CREATE EXTENSION IF NOT EXISTS hstore;
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;
+7
View File
@@ -0,0 +1,7 @@
[project]
name = "fitz-studio"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
View File
+30
View File
@@ -0,0 +1,30 @@
import os
def generate_tree(start_path='.', max_depth=2):
lines = []
def _tree(dir_path, depth, prefix):
if depth > max_depth:
return
entries = sorted(os.listdir(dir_path))
for i, entry in enumerate(entries):
path = os.path.join(dir_path, entry)
connector = "└── " if i == len(entries) - 1 else "├── "
lines.append(prefix + connector + entry)
if os.path.isdir(path):
extension = " " if i == len(entries) - 1 else ""
_tree(path, depth + 1, prefix + extension)
lines.append(start_path)
_tree(start_path, 1, '')
return '\n'.join(lines)
def save_tree_to_file(start_path='.', max_depth=2, output_file='tree.txt'):
tree_output = generate_tree(start_path, max_depth)
with open(output_file, 'w', encoding='utf-8') as f:
f.write(tree_output)
print(f"Árbol guardado en: {output_file}")
# Ejemplo de uso:
# 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')
+44
View File
@@ -0,0 +1,44 @@
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
class Encriptar_fernet:
@staticmethod
def _derivar_clave(password: str, salt: bytes) -> bytes:
"""
Deriva una clave segura a partir de la contraseña y el salt usando PBKDF2HMAC.
"""
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100_000,
backend=default_backend()
)
return base64.urlsafe_b64encode(kdf.derive(password.encode()))
@classmethod
def encriptar(cls, texto: str, password: str) -> bytes:
"""
Encripta un texto con una clave derivada de la contraseña + salt aleatorio.
El salt es embebido al inicio del token cifrado.
"""
salt = os.urandom(16) # 128 bits de salt aleatorio
key = cls._derivar_clave(password, salt)
fernet = Fernet(key)
token = fernet.encrypt(texto.encode('utf-8'))
return salt + token # Embebemos el salt al principio
@classmethod
def desencriptar(cls, token_con_salt: bytes, password: str) -> str:
"""
Extrae el salt del token, deriva la clave, y desencripta el texto.
"""
salt = token_con_salt[:16]
token = token_con_salt[16:]
key = cls._derivar_clave(password, salt)
fernet = Fernet(key)
return fernet.decrypt(token).decode('utf-8')
View File
+70
View File
@@ -0,0 +1,70 @@
import os
import random
import pandas as pd
from dotenv import load_dotenv
from entrypoint import ENV_PATH
# Cargar variables de entorno desde ENV_PATH
load_dotenv(ENV_PATH)
class GeneradorNombre_Spanish:
def __init__(self):
# Obtener ruta base del proyecto
project_path = os.getenv("PROJECT_PATH")
if not project_path:
raise ValueError("La variable PROJECT_PATH no está definida en el archivo .env")
# Construir rutas absolutas a los archivos
self.ruta_hombres = os.path.join(project_path, "data", "files", "txt", "nombres_español", "hombres.csv")
self.ruta_mujeres = os.path.join(project_path, "data", "files", "txt", "nombres_español", "mujeres.csv")
self.ruta_apellidos = os.path.join(project_path, "data", "files", "txt", "nombres_español", "apellidos.csv")
# Cargar datos
self.df_hombres = pd.read_csv(self.ruta_hombres)
self.df_mujeres = pd.read_csv(self.ruta_mujeres)
self.df_apellidos = pd.read_csv(self.ruta_apellidos)
# Limpiar y normalizar columnas
for df in (self.df_hombres, self.df_mujeres):
df.columns = df.columns.str.strip().str.lower()
df['frec'] = pd.to_numeric(df['frec'], errors='coerce')
df['edad_media'] = pd.to_numeric(df['edad_media'], errors='coerce')
df.dropna(subset=['frec', 'edad_media'], inplace=True)
self.df_apellidos.columns = self.df_apellidos.columns.str.strip().str.lower()
self.df_apellidos['frec_pri'] = pd.to_numeric(self.df_apellidos['frec_pri'], errors='coerce')
self.df_apellidos['frec_seg'] = pd.to_numeric(self.df_apellidos['frec_seg'], errors='coerce')
self.df_apellidos.dropna(subset=['frec_pri', 'frec_seg'], inplace=True)
def generar_nombre(self, sexo: str = None, edad_aprox: float = None) -> str:
if sexo not in {'hombre', 'mujer'}:
sexo = random.choice(['hombre', 'mujer'])
df = self.df_hombres if sexo == 'hombre' else self.df_mujeres
if edad_aprox is not None:
df = df[
(df['edad_media'] >= edad_aprox - 5) &
(df['edad_media'] <= edad_aprox + 5)
]
if df.empty:
raise ValueError(f"No hay nombres disponibles para edad {edad_aprox} y sexo {sexo}")
nombre = random.choices(df['nombre'].tolist(), weights=df['frec'].tolist(), k=1)[0]
return nombre
def generar_nombre_completo(self, sexo: str = None, edad_aprox: float = None) -> str:
nombre = self.generar_nombre(sexo, edad_aprox)
primer_apellido = random.choices(
self.df_apellidos['apellido'].tolist(),
weights=self.df_apellidos['frec_pri'].tolist(), k=1
)[0]
segundo_apellido = random.choices(
self.df_apellidos['apellido'].tolist(),
weights=self.df_apellidos['frec_seg'].tolist(), k=1
)[0]
return f"{nombre} {primer_apellido} {segundo_apellido}"
View File