|
from langchain_groq import ChatGroq |
|
from langchain_openai import ChatOpenAI |
|
from langchain_community.embeddings import HuggingFaceEmbeddings |
|
|
|
from langchain_pinecone import PineconeVectorStore |
|
from langchain_core.output_parsers import JsonOutputParser, StrOutputParser |
|
from langchain_core.prompts import ChatPromptTemplate |
|
from streamlit_option_menu import option_menu |
|
|
|
from elevenlabs.client import ElevenLabs |
|
from supabase import create_client, Client |
|
from openai import OpenAI |
|
from dotenv import load_dotenv |
|
|
|
import os |
|
import time |
|
import streamlit as st |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@st.cache_resource() |
|
def load_embedding_model(model_name): |
|
return HuggingFaceEmbeddings(model_name=model_name) |
|
|
|
|
|
def configuracion(): |
|
|
|
|
|
st.header(":gear: Configuración", divider='gray') |
|
|
|
|
|
hf_token = os.getenv('HF_TOKEN') |
|
groq_api_key = os.getenv('GROQ_API_KEY') |
|
openai_api_key = os.getenv('OPENAI_API_KEY') |
|
pinecone_api_key = os.getenv('PINECONE_API_KEY') |
|
supabase_key = os.getenv('SUPABASE_KEY') |
|
supabase_url = os.getenv('SUPABASE_URL') |
|
eleven_api_key = os.getenv('ELEVEN_API_KEY') |
|
langsmith_api_key = os.getenv('LANGSMITH_API_KEY') |
|
langchain_project = os.getenv('LANGCHAIN_PROJECT') |
|
langchain_tracing_v2 = os.getenv('LANGCHAIN_TRACING_V2') |
|
|
|
|
|
modelos_llm = [ |
|
'llama3-8b-8192', |
|
'llama3-70b-8192', |
|
'mixtral-8x7b-32768', |
|
'gemma-7b-it', |
|
'gpt-4o', |
|
] |
|
modelo_llm = st.selectbox('Modelo de lenguaje', list(modelos_llm), help="Especifica el modelo de lenguaje utilizado") |
|
|
|
|
|
temperature = st.slider("Temperatura", 0.0, 2.0, 1.0, disabled=True, step=0.1) |
|
|
|
if modelo_llm == "gpt-4o": |
|
llm = ChatOpenAI(model=modelo_llm) |
|
llm_creative = ChatOpenAI(model=modelo_llm, temperature=temperature) |
|
else: |
|
llm = ChatGroq(model=modelo_llm) |
|
llm_creative = ChatGroq(model=modelo_llm, temperature=temperature) |
|
|
|
|
|
model_name = 'intfloat/multilingual-e5-small' |
|
model_name = st.text_input("Modelo de embedding:", value=model_name, disabled=True, help="Indica el modelo de _embedding_ utilizado en la vectorstore") |
|
|
|
embedding = load_embedding_model(model_name) |
|
|
|
|
|
index_name = "poemas-intfloat-multilingual-e5-small" |
|
namespace = "poesiacastellana" |
|
vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding) |
|
col1, col2 = st.columns(2) |
|
with col1: |
|
input1 = st.text_input("Index", value=index_name, disabled=True, help="Nombre del _index_ del vectorstore en Pinecone para RAG") |
|
with col2: |
|
input2 = st.text_input("namespace", value=namespace, disabled=True, help="Nombre del _namespace_ del vectorstore en Pinecone") |
|
|
|
|
|
url: str = os.environ.get("SUPABASE_URL") |
|
key: str = os.environ.get("SUPABASE_KEY") |
|
supabase: Client = create_client(url, key) |
|
|
|
|
|
st.session_state.modelo_llm = modelo_llm |
|
st.session_state.temperature = temperature |
|
st.session_state.llm = llm |
|
st.session_state.llm_creative = llm_creative |
|
st.session_state.embedding = embedding |
|
st.session_state.db = vectorstore |
|
st.session_state.supabase = supabase |
|
|
|
|
|
with st.expander("API Keys"): |
|
GROQ_API_KEY = st.text_input('Groq API Key', value=groq_api_key, type='password') |
|
OPENAI_API_KEY = st.text_input('OpenAI API Key', value=openai_api_key, type='password') |
|
HF_TOKEN = st.text_input('HuggingFace API Key', value=hf_token, type='password') |
|
PINECONE_API_KEY = st.text_input('Pinecone API Key', value=pinecone_api_key, type='password') |
|
ELEVEN_API_KEY = st.text_input('ElevenLabs API Key', value=eleven_api_key, type='password') |
|
|
|
|
|
|
|
|
|
@st.cache_resource() |
|
def __init__(): |
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
llm_images = OpenAI() |
|
|
|
|
|
modelo_llm = 'llama3-8b-8192' |
|
temperature = 1 |
|
llm = ChatGroq(model=modelo_llm) |
|
llm_creative = ChatGroq(model=modelo_llm, temperature=temperature) |
|
|
|
|
|
model_name = 'intfloat/multilingual-e5-small' |
|
embedding = load_embedding_model(model_name) |
|
|
|
|
|
index_name = "poemas-intfloat-multilingual-e5-small" |
|
namespace = "poesiacastellana" |
|
vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding) |
|
|
|
|
|
url: str = os.environ.get("SUPABASE_URL") |
|
key: str = os.environ.get("SUPABASE_KEY") |
|
supabase: Client = create_client(url, key) |
|
|
|
|
|
st.session_state.modelo_llm = modelo_llm |
|
st.session_state.temperature = temperature |
|
st.session_state.llm = llm |
|
st.session_state.llm_creative = llm_creative |
|
st.session_state.llm_images = llm_images |
|
st.session_state.embedding = embedding |
|
st.session_state.db = vectorstore |
|
st.session_state.supabase = supabase |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def grafo(): |
|
|
|
|
|
col1, col2 = st.columns([4,20]) |
|
with col1: |
|
st.image("img/bot.png", width=100) |
|
with col2: |
|
st.title("Generador de poemas") |
|
|
|
|
|
tema_suggestions = ["Amor", "Vida", "Misterio", "Aventura", "Sueños", "Amistad", "Impermanencia"] |
|
estilo_suggestions = ["Romántico", "Gótico", "Épico", "Lírico", "Soneto", "Haiku", "Verso libre", "Gen27"] |
|
|
|
|
|
tema = st.text_input("Tema:", value="el despertar de la conciencia", help="Especifa el *tema* sobre el que quieres escribir el poema") |
|
|
|
|
|
|
|
estilo = st.text_input("Estilo:", value="antonio machado", help="Especifa el *estilo* con el que quieres escribir el poema") |
|
|
|
|
|
|
|
with st.expander("Expertise Knowledge", icon="👩💻"): |
|
for item in st.session_state.expertise: |
|
st.markdown(f"```\n{item}\n```") |
|
|
|
|
|
if st.button("Generar Poema", type="primary", use_container_width=True): |
|
|
|
|
|
st.session_state.tema = tema |
|
st.session_state.estilo = estilo |
|
st.session_state.professor = ["No hay revisiones del profesor."] |
|
|
|
|
|
with st.spinner("Recuperando conocimiento aumentado..."): |
|
rag_retrieval() |
|
pass |
|
st.success(":floppy_disk: ¡Conocimiento aumentado recuperado!") |
|
|
|
|
|
with st.spinner("Generando conocimiento experto..."): |
|
generated_knowledge() |
|
pass |
|
st.success(":notebook: ¡Conocimiento experto generado!") |
|
|
|
|
|
with st.spinner("Generando borrador poético..."): |
|
draft_poem() |
|
pass |
|
st.success(":memo: ¡Borrador poético generado!") |
|
|
|
|
|
with st.spinner("El catedrático está revisando el borrador poético..."): |
|
reflexion_catedratico() |
|
pass |
|
st.success(":female-student: ¡Borrador poético revisado!") |
|
|
|
|
|
with st.spinner("Generando el poema..."): |
|
st.session_state.poema = final_poem(st.session_state.draft_poem, st.session_state.reflexion) |
|
pass |
|
st.success(":scroll: ¡Poema generado!") |
|
|
|
|
|
almacenar("insert") |
|
|
|
|
|
st.markdown(f"```\n{st.session_state.poema}\n```") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rag_retrieval(): |
|
|
|
|
|
filter = {} |
|
|
|
|
|
k=20 |
|
|
|
|
|
tema = st.session_state.tema |
|
|
|
|
|
documents = st.session_state.db.similarity_search(tema, k=k, filter=filter) |
|
|
|
|
|
rag_poems = [doc.page_content for doc in documents] |
|
|
|
|
|
st.session_state.rag = rag_poems |
|
|
|
|
|
|
|
def expertise_knowledge(): |
|
|
|
|
|
st.header(":female-technologist: Expertise Knowledge (HITL)", divider='red') |
|
|
|
|
|
poema = st.text_area("Poema de referencia", height=300, help="Añade aquí los poemas de referencia que sirvan como ejemplo para la elaboración del poema. Pulsa _Actualziar_ para limpiar el conjunto de poemas existente.") |
|
|
|
|
|
col1, col2 = st.columns(2, gap="small") |
|
with col1: |
|
if st.button("Añadir", use_container_width=True): |
|
st.session_state.expertise.insert(0, f"Poema:\n{poema.strip()}") |
|
poema = "" |
|
with col2: |
|
if st.button("Actualizar", type="primary", use_container_width=True): |
|
st.session_state.expertise = [f"Poema:\n{poema.strip()}"] |
|
poema = "" |
|
|
|
|
|
st.divider() |
|
|
|
for poem in st.session_state.expertise: |
|
st.markdown(f"```\n{poem}\n```") |
|
|
|
|
|
|
|
def generated_knowledge(): |
|
|
|
|
|
system = """ |
|
Eres un ratón de biblioteca y un profesor experto de literatura de una prestigiosa universidad con gran capacidad de \ |
|
sintetizar características de corrientes y estilos literarios. Tu objetivo es proporcionar las características principales \ |
|
y los detalles de las consultas académicas que te hagan sobre el estilo poético de '''{style_of}'''. Escribe las \ |
|
características principales sobre el estilo literario, movimiento o generación definido en el estilo o en el poeta nombrado, \ |
|
que sirvan de guía para la elaboración de nuevos textos que imiten el estilo indicado o al poeta solicitado. |
|
|
|
Es importante que no escribas ningún poema, tan solo enumera un listado detallado de características, que sean útiles \ |
|
para poder reproducirse y aplicarse en la generación de nuevos textos. |
|
""" |
|
human = 'Devuelve SOLO un listado detallado de las características en formato JSON. \ |
|
Formato: {{ "Características": ["característica 1", "característica 2", "característica 3"]}}' |
|
|
|
prompt = ChatPromptTemplate.from_messages([ |
|
("system", system), |
|
("human", human), |
|
]) |
|
|
|
|
|
style_of = st.session_state.estilo |
|
|
|
|
|
chain = prompt | st.session_state.llm | JsonOutputParser() |
|
knowledge = chain.invoke({"style_of": style_of}) |
|
|
|
|
|
knowledge_values = list(knowledge.values())[0] |
|
|
|
|
|
st.session_state.generated = knowledge_values |
|
|
|
|
|
|
|
def draft_poem(): |
|
|
|
|
|
system = """ |
|
Eres un maestro de la poesía, capaz de escribir poemas que evocan emociones poderosas y obras maestras poéticas \ |
|
que capten la esencia del tema especificado de forma profunda y evocadora. Escribes desde la belleza. Cada línea \ |
|
cuidadosamente elaborada proyecta una imagen vívida, evocando emociones fuertes y hermosas con una destreza poética \ |
|
que deja sin aliento al lector. Tu estilo es una fusión de metáforas, aliteración y cadencia rítmica. |
|
|
|
Las imágenes que evocan tus palabras son originales, creativas y únicas, alejándose de los tópicos y dotadas de un \ |
|
significado profundo y auténtico. Tus poemas están escritos para recitarse y leerse en voz alta. Se hace hincapié en \ |
|
que la escritura sea vívida y detallada, al tiempo que se garantiza que los poemas tengan un mensaje profundo que \ |
|
resuene en el lector mucho después de que haya terminado de leerlos. El objetivo es crear una poesía impactante y \ |
|
bella que deje una impresión duradera en el público. |
|
|
|
Haces un uso de la rima es muy sutil, SOLO la utilizas cuando es necesaria. Si las características proporcionadas no \ |
|
indican lo contrario, haz un uso responsable y limitado de ella. |
|
|
|
Esta es una lista de poemas que debes utilizar como EJEMPLOS e inspiración para escribir el poema: |
|
'''{expertise}''' |
|
|
|
Aquí tienes una lista de poemas con una temática similar que puedes usar para inspirarte: |
|
''' |
|
{rag_poems} |
|
''' |
|
""" |
|
human = ( |
|
"El poema debe escribirse atendiendo a las siguientes CARACTERÍSTICAS: " |
|
"\n'''" |
|
"\n * 18 versos o menos, no debes superar NUNCA esta cantidad " |
|
"\n * {knowledge} " |
|
"\n''' " |
|
"\n\nEscribe un BREVE poema de menos de 18 versos sobre el tema de '''{topic}'''. " |
|
"No hagas comentarios. " + "Esto es muy importante para mi carrera." |
|
) |
|
|
|
prompt = ChatPromptTemplate.from_messages([ |
|
("system", system), |
|
("human", human), |
|
]) |
|
|
|
|
|
topic = st.session_state.tema |
|
knowledge = st.session_state.generated |
|
expertise = st.session_state.expertise |
|
rag_poems = st.session_state.rag |
|
|
|
|
|
knowledge = '\n * '.join(knowledge) |
|
expertise = ' '.join(expertise) |
|
rag_poems = ' '.join(rag_poems) |
|
|
|
|
|
chain = prompt | st.session_state.llm_creative | StrOutputParser() |
|
draft_poem = chain.invoke({"topic": topic, "knowledge": knowledge, "expertise": expertise, "rag_poems": rag_poems}) |
|
|
|
|
|
st.session_state.draft_poem = draft_poem |
|
|
|
|
|
|
|
|
|
def final_poem(poema, review): |
|
|
|
|
|
system = """ |
|
Eres un experto escritor de poesía que mejora los poemas. Tu objetivo es reescribir el poema proporcionado \ |
|
a partir de los comentarios proporcionadas por el profesor experto. \ |
|
|
|
POEMA: |
|
''' |
|
{poema} |
|
''' |
|
|
|
COMENTARIOS del profesor experto: |
|
''' |
|
* {review} |
|
''' |
|
""" |
|
human=( |
|
"Escribe solo el poema final mejorado, el mejor posible. " |
|
"No hagas comentarios, ni aclaraciones sobre lo que has modificado. Esto es muy importante para mi carrera." |
|
) |
|
|
|
prompt = ChatPromptTemplate.from_messages([ |
|
("system", system), |
|
("human", human), |
|
]) |
|
|
|
|
|
review = '\n * '.join(list(review)) |
|
|
|
|
|
chain = prompt | st.session_state.llm_creative | StrOutputParser() |
|
final_poem = chain.invoke({"poema": poema, "review": review}) |
|
|
|
|
|
return final_poem |
|
|
|
|
|
|
|
|
|
def reflexion_catedratico(): |
|
|
|
|
|
system = """ |
|
Eres un catedrático experto en poesía de una prestigiosa universidad con un profundo conocimiento y experiencia \ |
|
en el análisis de poemas. Tienes ojo crítico y una pasión por la perfección literaria. Tu objetivo es revisar y \ |
|
sugerir mejoras para los poemas. |
|
|
|
Evalúas y analizas la calidad del poema recibido y proporcionas comentarios constructivos que permitan mejorar el resultado final. |
|
|
|
Este es el poema: |
|
''' |
|
{draft_poem} |
|
''' |
|
""" |
|
|
|
human = 'Devuelve SOLO un listado detallado de los comentarios en formato JSON. \ |
|
Formato: {{ "comentarios": ["comentario 1", "comentario 2", "comentario 3"]}}' |
|
|
|
prompt = ChatPromptTemplate.from_messages([ |
|
("system", system), |
|
("human", human), |
|
]) |
|
|
|
|
|
draft_poem = st.session_state.draft_poem |
|
|
|
|
|
chain = prompt | st.session_state.llm | JsonOutputParser() |
|
reflexion = chain.invoke({"draft_poem": draft_poem}) |
|
|
|
|
|
comentarios = list(reflexion.values())[0] |
|
|
|
|
|
st.session_state.reflexion = comentarios |
|
|
|
|
|
|
|
def professor_reflexion(): |
|
st.header(":female-student: Professor Reflexion (HITL)", divider='red') |
|
|
|
|
|
st.write("Poema") |
|
st.markdown(f"```\n{st.session_state.poema}\n```") |
|
|
|
|
|
if st.session_state.poema != "No hay poema elaborado.": |
|
|
|
col1, col2 = st.columns(2) |
|
with col1: |
|
|
|
voz = st.button("Recitar", use_container_width=True, help="Recita el poema en alto") |
|
with col2: |
|
|
|
imagen = st.button("Imaginar", use_container_width=True, help="Genera una imagen a partir del poema") |
|
|
|
if voz: |
|
try: |
|
|
|
audio = recitar(st.session_state.poema) |
|
st.audio(audio, format="audio/mp3") |
|
except Exception as e: |
|
|
|
st.error(f"No dispones de créditos suficientes para realizar esta operación.") |
|
|
|
if imagen: |
|
try: |
|
|
|
url_imagen, enlace = pintar(st.session_state.draft_poem) |
|
|
|
st.image(url_imagen, use_column_width="always") |
|
st.markdown(enlace, unsafe_allow_html=True) |
|
except Exception as e: |
|
|
|
st.error(f"No dispones de créditos suficientes para realizar esta operación.") |
|
|
|
|
|
|
|
professor = st.text_area("Comentarios, crítica y sugerencias", help="Escribe aquí la revisión experta del catedrático.") |
|
|
|
|
|
if st.button("Escribir", type="primary", use_container_width=True): |
|
|
|
st.session_state.professor = [professor] |
|
st.session_state.expert_poem = st.session_state.poema |
|
|
|
with st.spinner("Reformando el poema..."): |
|
st.session_state.poema = final_poem(st.session_state.poema, professor) |
|
pass |
|
st.success("¡Poema reformado! :thumbsup:") |
|
|
|
|
|
almacenar("update") |
|
|
|
|
|
st.markdown(f"```{st.session_state.poema}```") |
|
|
|
|
|
|
|
|
|
@st.cache_resource() |
|
def pintar(poema): |
|
|
|
|
|
prompt = "Dibuja una imagen que represente de forma abstracta el siguiente poema. No incluyas NINGUN texto. No incluyas texto. POEMA:" + poema |
|
response = st.session_state.llm_images.images.generate( |
|
model="dall-e-3", |
|
prompt=prompt, |
|
size="1024x1024", |
|
quality="standard", |
|
n=1, |
|
) |
|
|
|
|
|
url_imagen = response.data[0].url |
|
|
|
|
|
link_text = "Haz clic aquí para ver la imagen en grande" |
|
link = f'[{link_text}]({url_imagen})' |
|
|
|
return url_imagen, link |
|
|
|
|
|
|
|
|
|
@st.cache_resource() |
|
def recitar(poema): |
|
|
|
eleven_api_key = os.environ.get("ELEVEN_API_KEY") |
|
|
|
client = ElevenLabs( |
|
api_key=eleven_api_key, |
|
) |
|
|
|
audio = client.generate( |
|
text=poema, |
|
voice="Sara Martin 3", |
|
model="eleven_multilingual_v2" |
|
) |
|
|
|
audio_bytes = b'' |
|
for chunk in audio: |
|
audio_bytes += chunk |
|
|
|
return audio_bytes |
|
|
|
|
|
|
|
def almacenar(accion): |
|
|
|
|
|
data = { |
|
"model": st.session_state.modelo_llm, |
|
"temperature": st.session_state.temperature, |
|
"topic": st.session_state.tema, |
|
"style_of": st.session_state.estilo, |
|
"knowledge": st.session_state.generated, |
|
"expertise": st.session_state.expertise, |
|
"rag_poems": st.session_state.rag, |
|
"draft_poem": st.session_state.draft_poem, |
|
"draft_poem_fb": st.session_state.reflexion, |
|
"professor": st.session_state.professor, |
|
"final_poem": st.session_state.poema, |
|
} |
|
|
|
|
|
if accion == "insert": |
|
|
|
data, count = st.session_state.supabase.table("Poemas").insert(data).execute() |
|
|
|
st.session_state.id = data[1][0]['id'] |
|
|
|
if accion == "update": |
|
id = st.session_state.id |
|
data, count = st.session_state.supabase.table("Poemas").update(data).eq("id", id).execute() |
|
|
|
|
|
|
|
|
|
def resumen(): |
|
|
|
st.header(":memo: Metodología desarrollada", divider='gray') |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
with col1: |
|
input1 = st.text_input("Tema", value=st.session_state.tema, disabled=True) |
|
with col2: |
|
input2 = st.text_input("Estilo", value=st.session_state.estilo, disabled=True) |
|
|
|
|
|
st.subheader('Contexto', divider='red', help="Se muestra el *contexto* generado que se incrustará en el _prompt_") |
|
|
|
|
|
with st.expander("Expertise Knowledge (HITL)", icon="👩💻"): |
|
for item in st.session_state.expertise: |
|
st.markdown(f"```\n{item}\n```") |
|
|
|
|
|
with st.expander("Conocimiento generado", icon="💻"): |
|
for item in st.session_state.generated: |
|
st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True) |
|
|
|
|
|
with st.expander("Conocimiento recuperado", icon="💾"): |
|
for item in st.session_state.rag: |
|
st.markdown(f"```\n{item}\n```") |
|
|
|
|
|
st.subheader('Reflexión', divider='red', help="Se muestra el borrador poético y las reflexiones de los expertos") |
|
|
|
|
|
with st.expander("Borrador poético", icon="📃"): |
|
st.markdown(f"```\n{st.session_state.draft_poem}\n```") |
|
|
|
|
|
with st.expander("Reflexión del catedrático", icon="🎓"): |
|
for item in st.session_state.reflexion: |
|
st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True) |
|
|
|
|
|
if "expert_poem" in st.session_state: |
|
with st.expander("Poema revisado", icon="📃"): |
|
st.markdown(f"```{st.session_state.expert_poem}```") |
|
|
|
|
|
if "professor" in st.session_state: |
|
with st.expander("Reflexión del profesor (HITL)", icon="👩🎓"): |
|
for item in st.session_state.professor: |
|
st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True) |
|
|
|
|
|
st.subheader('Poema :scroll:', divider='rainbow', help="Se muestra el poema elaborado") |
|
|
|
|
|
st.markdown(f"```\n{st.session_state.poema}\n```") |
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
st.set_page_config(page_title="Generador de poemas") |
|
|
|
if "draft_poem" not in st.session_state: |
|
st.session_state.draft_poem = "No hay borrador poético." |
|
|
|
|
|
st.session_state.poema = st.__version__ |
|
if "generated" not in st.session_state: |
|
st.session_state.generated = ["No hay conocimiento generado."] |
|
if "expertise" not in st.session_state: |
|
st.session_state.expertise = ["No hay conocimiento experto proporcionado."] |
|
if "rag" not in st.session_state: |
|
st.session_state.rag = ["No hay conocimiento aumentado por recuperación."] |
|
if "reflexion" not in st.session_state: |
|
st.session_state.reflexion = ["No hay revisiones del catedrático."] |
|
if "professor" not in st.session_state: |
|
st.session_state.professor = ["No hay revisiones del profesor."] |
|
if 'tema' not in st.session_state: |
|
st.session_state.tema = "" |
|
if 'estilo' not in st.session_state: |
|
st.session_state.estilo = "" |
|
|
|
|
|
__init__() |
|
|
|
|
|
opciones = { |
|
"Topic&Style": grafo, |
|
"Metodología": resumen, |
|
"Expertise (HITL)": expertise_knowledge, |
|
"Professor (HITL)": professor_reflexion, |
|
"Configuración": configuracion, |
|
} |
|
|
|
|
|
|
|
|
|
with st.sidebar: |
|
seleccion = option_menu(None, list(opciones.keys()), |
|
icons=['envelope-paper-heart','envelope-heart','person-hearts','person-square', 'gear'], |
|
menu_icon="cast", |
|
default_index=0) |
|
st.image("img/bot.webp", width=250) |
|
|
|
|
|
opciones[seleccion]() |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
main() |
|
|