segoedu commited on
Commit
811cd8b
·
verified ·
1 Parent(s): 8fdc7f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +711 -710
app.py CHANGED
@@ -1,710 +1,711 @@
1
- from langchain_groq import ChatGroq
2
- from langchain_openai import ChatOpenAI
3
- from langchain_community.embeddings import HuggingFaceEmbeddings
4
- #from langchain.chains import RetrievalQA
5
- from langchain_pinecone import PineconeVectorStore
6
- from langchain_core.output_parsers import JsonOutputParser, StrOutputParser
7
- from langchain_core.prompts import ChatPromptTemplate
8
- from streamlit_option_menu import option_menu
9
- #from elevenlabs import save, play, stream
10
- from elevenlabs.client import ElevenLabs
11
- from supabase import create_client, Client
12
- from openai import OpenAI
13
- from dotenv import load_dotenv
14
-
15
- import os
16
- import time
17
- import streamlit as st
18
-
19
-
20
-
21
- #####################
22
- # CONFIGURACIÓN #
23
- #####################
24
-
25
- # Función de configuración de embedding
26
- @st.cache_resource()
27
- def load_embedding_model(model_name):
28
- return HuggingFaceEmbeddings(model_name=model_name)
29
-
30
- # Función de configuración
31
- def configuracion():
32
-
33
- # Cabecera
34
- st.header(":gear: Configuración", divider='gray')
35
-
36
- # API Keys #
37
- hf_token = os.getenv('HF_TOKEN')
38
- groq_api_key = os.getenv('GROQ_API_KEY')
39
- openai_api_key = os.getenv('OPENAI_API_KEY')
40
- pinecone_api_key = os.getenv('PINECONE_API_KEY')
41
- supabase_key = os.getenv('SUPABASE_KEY')
42
- supabase_url = os.getenv('SUPABASE_URL')
43
- eleven_api_key = os.getenv('ELEVEN_API_KEY')
44
- langsmith_api_key = os.getenv('LANGSMITH_API_KEY')
45
- langchain_project = os.getenv('LANGCHAIN_PROJECT')
46
- langchain_tracing_v2 = os.getenv('LANGCHAIN_TRACING_V2')
47
-
48
- # Modelo de lenguaje #
49
- modelos_llm = [
50
- 'llama3-8b-8192',
51
- 'llama3-70b-8192',
52
- 'mixtral-8x7b-32768',
53
- 'gemma-7b-it',
54
- 'gpt-4o',
55
- ]
56
- modelo_llm = st.selectbox('Modelo de lenguaje', list(modelos_llm), help="Especifica el modelo de lenguaje utilizado")
57
-
58
- # Temperatura
59
- temperature = st.slider("Temperatura", 0.0, 2.0, 1.0, disabled=True, step=0.1)
60
-
61
- if modelo_llm == "gpt-4o":
62
- llm = ChatOpenAI(model=modelo_llm)
63
- llm_creative = ChatOpenAI(model=modelo_llm, temperature=temperature)
64
- else:
65
- llm = ChatGroq(model=modelo_llm)
66
- llm_creative = ChatGroq(model=modelo_llm, temperature=temperature)
67
-
68
- # Embeddings #
69
- model_name = 'intfloat/multilingual-e5-small'
70
- model_name = st.text_input("Modelo de embedding:", value=model_name, disabled=True, help="Indica el modelo de _embedding_ utilizado en la vectorstore")
71
- #embedding = HuggingFaceEmbeddings(model_name=model_name)
72
- embedding = load_embedding_model(model_name)
73
-
74
- # Pinecone #
75
- index_name = "poemas-intfloat-multilingual-e5-small"
76
- namespace = "poesiacastellana"
77
- vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding)
78
- col1, col2 = st.columns(2)
79
- with col1:
80
- input1 = st.text_input("Index", value=index_name, disabled=True, help="Nombre del _index_ del vectorstore en Pinecone para RAG")
81
- with col2:
82
- input2 = st.text_input("namespace", value=namespace, disabled=True, help="Nombre del _namespace_ del vectorstore en Pinecone")
83
-
84
- # Supabase #
85
- url: str = os.environ.get("SUPABASE_URL")
86
- key: str = os.environ.get("SUPABASE_KEY")
87
- supabase: Client = create_client(url, key)
88
-
89
- # Variables globales
90
- st.session_state.modelo_llm = modelo_llm
91
- st.session_state.temperature = temperature
92
- st.session_state.llm = llm
93
- st.session_state.llm_creative = llm_creative
94
- st.session_state.embedding = embedding
95
- st.session_state.db = vectorstore
96
- st.session_state.supabase = supabase
97
-
98
- # API Keys #
99
- with st.expander("API Keys"):
100
- GROQ_API_KEY = st.text_input('Groq API Key', value=groq_api_key, type='password')
101
- OPENAI_API_KEY = st.text_input('OpenAI API Key', value=openai_api_key, type='password')
102
- HF_TOKEN = st.text_input('HuggingFace API Key', value=hf_token, type='password')
103
- PINECONE_API_KEY = st.text_input('Pinecone API Key', value=pinecone_api_key, type='password')
104
- ELEVEN_API_KEY = st.text_input('ElevenLabs API Key', value=eleven_api_key, type='password')
105
-
106
-
107
-
108
- # ----- Función de configuración -----------------------------------------------------------
109
- @st.cache_resource()
110
- def __init__():
111
-
112
- # API Keys #
113
- load_dotenv()
114
-
115
- # Modelo de lenguaje multimodal
116
- llm_images = OpenAI()
117
-
118
- # Modelo de lenguaje
119
- modelo_llm = 'llama3-8b-8192'
120
- temperature = 1
121
- llm = ChatGroq(model=modelo_llm)
122
- llm_creative = ChatGroq(model=modelo_llm, temperature=temperature)
123
-
124
- # Embeddings
125
- model_name = 'intfloat/multilingual-e5-small'
126
- embedding = load_embedding_model(model_name)
127
-
128
- # Pinecone
129
- index_name = "poemas-intfloat-multilingual-e5-small"
130
- namespace = "poesiacastellana"
131
- vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding)
132
-
133
- # Supabase
134
- url: str = os.environ.get("SUPABASE_URL")
135
- key: str = os.environ.get("SUPABASE_KEY")
136
- supabase: Client = create_client(url, key)
137
-
138
- # Globals
139
- st.session_state.modelo_llm = modelo_llm
140
- st.session_state.temperature = temperature
141
- st.session_state.llm = llm
142
- st.session_state.llm_creative = llm_creative
143
- st.session_state.llm_images = llm_images
144
- st.session_state.embedding = embedding
145
- st.session_state.db = vectorstore
146
- st.session_state.supabase = supabase
147
-
148
-
149
- #####################
150
- # GRAFO #
151
- #####################
152
-
153
- # ----- Función para desarrollar la metodología ------------------------------------------------
154
- def grafo():
155
-
156
- # Añadir una imagen al lado del título
157
- col1, col2 = st.columns([4,20])
158
- with col1:
159
- st.image("img/bot.png", width=100)
160
- with col2:
161
- st.title("Generador de poemas")
162
-
163
- # Botones de sugerencia para el tema/estilo
164
- tema_suggestions = ["Amor", "Vida", "Misterio", "Aventura", "Sueños", "Amistad", "Impermanencia"]
165
- estilo_suggestions = ["Romántico", "Gótico", "Épico", "Lírico", "Soneto", "Haiku", "Verso libre", "Gen27"]
166
-
167
- # Campo para el tema
168
- tema = st.text_input("Tema:", value="el despertar de la conciencia", help="Especifa el *tema* sobre el que quieres escribir el poema")
169
- #tema_seleccionado = st.multiselect("Selecciona las opciones deseadas:", tema_suggestions)
170
-
171
- # Campo para el estilo/estructura
172
- estilo = st.text_input("Estilo:", value="antonio machado", help="Especifa el *estilo* con el que quieres escribir el poema")
173
- #estilo_seleccionado = st.multiselect("Selecciona las opciones deseadas:", estilo_suggestions)
174
-
175
- # Mostrar el conocimiento experto
176
- with st.expander("Expertise Knowledge", icon="👩‍💻"):
177
- for item in st.session_state.expertise:
178
- st.markdown(f"```\n{item}\n```")
179
-
180
- # Botón para generar el poema
181
- if st.button("Generar Poema", type="primary", use_container_width=True):
182
-
183
- # Variables globales
184
- st.session_state.tema = tema
185
- st.session_state.estilo = estilo
186
- st.session_state.professor = ["No hay revisiones del profesor."]
187
-
188
- # Generación del contexto
189
- with st.spinner("Recuperando conocimiento aumentado..."):
190
- rag_retrieval()
191
- pass
192
- st.success(":floppy_disk: ¡Conocimiento aumentado recuperado!")
193
-
194
- # Generación del conocimiento
195
- with st.spinner("Generando conocimiento experto..."):
196
- generated_knowledge()
197
- pass
198
- st.success(":notebook: ¡Conocimiento experto generado!")
199
-
200
- # Generación del borrador poético
201
- with st.spinner("Generando borrador poético..."):
202
- draft_poem()
203
- pass
204
- st.success(":memo: ¡Borrador poético generado!")
205
-
206
- # Generando reflexion
207
- with st.spinner("El catedrático está revisando el borrador poético..."):
208
- reflexion_catedratico()
209
- pass
210
- st.success(":female-student: ¡Borrador poético revisado!")
211
-
212
- # Generando poema
213
- with st.spinner("Generando el poema..."):
214
- st.session_state.poema = final_poem(st.session_state.draft_poem, st.session_state.reflexion)
215
- pass
216
- st.success(":scroll: ¡Poema generado!")
217
-
218
- # Almacenar poema en Supabase
219
- almacenar("insert")
220
-
221
- # Mostrar poema
222
- st.markdown(f"```\n{st.session_state.poema}\n```")
223
-
224
-
225
- #####################
226
- # AGENTES #
227
- #####################
228
-
229
- # ----- Función para mostrar la recuperación aumentada -----------------------------------
230
- def rag_retrieval():
231
-
232
- # Define the filter condition based on the 'author' metadata field
233
- filter = {}
234
-
235
- # Define el número de resultados
236
- k=20
237
-
238
- # Recupera los valores del grafo
239
- tema = st.session_state.tema
240
-
241
- # Perform the search: topic, human
242
- documents = st.session_state.db.similarity_search(tema, k=k, filter=filter) #db.similarity_search_with_score
243
-
244
- # Armamos la lista
245
- rag_poems = [doc.page_content for doc in documents]
246
-
247
- # Variable global
248
- st.session_state.rag = rag_poems
249
-
250
-
251
- # ----- Función para mostrar el conocimiento experto -------------------------------------
252
- def expertise_knowledge():
253
-
254
- # Mostramos una cabecera
255
- st.header(":female-technologist: Expertise Knowledge (HITL)", divider='red')
256
-
257
- # Campo de texto para ingresar poemas
258
- 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.")
259
-
260
- # Botones para añadir y actualizar
261
- col1, col2 = st.columns(2, gap="small")
262
- with col1:
263
- if st.button("Añadir", use_container_width=True):
264
- st.session_state.expertise.insert(0, f"Poema:\n{poema.strip()}")
265
- poema = "" # Limpiar el campo poema
266
- with col2:
267
- if st.button("Actualizar", type="primary", use_container_width=True):
268
- st.session_state.expertise = [f"Poema:\n{poema.strip()}"]
269
- poema = "" # Limpiar el campo poema
270
-
271
- # Mostrar el conocimiento experto
272
- st.divider()
273
- #st.write("Expertise Knowledge:")
274
- for poem in st.session_state.expertise:
275
- st.markdown(f"```\n{poem}\n```")
276
-
277
-
278
- # ----- Función para mostrar el conocimiento generado -------------------------------------
279
- def generated_knowledge():
280
-
281
- # Armamos el prompt
282
- system = """
283
- Eres un ratón de biblioteca y un profesor experto de literatura de una prestigiosa universidad con gran capacidad de \
284
- sintetizar características de corrientes y estilos literarios. Tu objetivo es proporcionar las características principales \
285
- y los detalles de las consultas académicas que te hagan sobre el estilo poético de '''{style_of}'''. Escribe las \
286
- características principales sobre el estilo literario, movimiento o generación definido en el estilo o en el poeta nombrado, \
287
- que sirvan de guía para la elaboración de nuevos textos que imiten el estilo indicado o al poeta solicitado.
288
-
289
- Es importante que no escribas ningún poema, tan solo enumera un listado detallado de características, que sean útiles \
290
- para poder reproducirse y aplicarse en la generación de nuevos textos.
291
- """
292
- human = 'Devuelve SOLO un listado detallado de las características en formato JSON. \
293
- Formato: {{ "Características": ["característica 1", "característica 2", "característica 3"]}}'
294
-
295
- prompt = ChatPromptTemplate.from_messages([
296
- ("system", system),
297
- ("human", human),
298
- ])
299
-
300
- # Recupera los valores del grafo
301
- style_of = st.session_state.estilo
302
-
303
- # Lanzamos la consulta
304
- chain = prompt | st.session_state.llm | JsonOutputParser()
305
- knowledge = chain.invoke({"style_of": style_of})
306
-
307
- # Parser
308
- knowledge_values = list(knowledge.values())[0]
309
-
310
- # Valor global
311
- st.session_state.generated = knowledge_values
312
-
313
-
314
- # ----- Función para generar el borrado poético------ -------------------------------------
315
- def draft_poem():
316
-
317
- # Armamos el prompt
318
- system = """
319
- Eres un maestro de la poesía, capaz de escribir poemas que evocan emociones poderosas y obras maestras poéticas \
320
- que capten la esencia del tema especificado de forma profunda y evocadora. Escribes desde la belleza. Cada línea \
321
- cuidadosamente elaborada proyecta una imagen vívida, evocando emociones fuertes y hermosas con una destreza poética \
322
- que deja sin aliento al lector. Tu estilo es una fusión de metáforas, aliteración y cadencia rítmica.
323
-
324
- Las imágenes que evocan tus palabras son originales, creativas y únicas, alejándose de los tópicos y dotadas de un \
325
- significado profundo y auténtico. Tus poemas están escritos para recitarse y leerse en voz alta. Se hace hincapié en \
326
- que la escritura sea vívida y detallada, al tiempo que se garantiza que los poemas tengan un mensaje profundo que \
327
- resuene en el lector mucho después de que haya terminado de leerlos. El objetivo es crear una poesía impactante y \
328
- bella que deje una impresión duradera en el público.
329
-
330
- Haces un uso de la rima es muy sutil, SOLO la utilizas cuando es necesaria. Si las características proporcionadas no \
331
- indican lo contrario, haz un uso responsable y limitado de ella.
332
-
333
- Esta es una lista de poemas que debes utilizar como EJEMPLOS e inspiración para escribir el poema:
334
- '''{expertise}'''
335
-
336
- Aquí tienes una lista de poemas con una temática similar que puedes usar para inspirarte:
337
- '''
338
- {rag_poems}
339
- '''
340
- """
341
- human = (
342
- "El poema debe escribirse atendiendo a las siguientes CARACTERÍSTICAS: "
343
- "\n'''"
344
- "\n * 18 versos o menos, no debes superar NUNCA esta cantidad "
345
- "\n * {knowledge} "
346
- "\n''' "
347
- "\n\nEscribe un BREVE poema de menos de 18 versos sobre el tema de '''{topic}'''. "
348
- "No hagas comentarios. " + "Esto es muy importante para mi carrera."
349
- )
350
-
351
- prompt = ChatPromptTemplate.from_messages([
352
- ("system", system),
353
- ("human", human),
354
- ])
355
-
356
- # Recupera los valores del grafo
357
- topic = st.session_state.tema
358
- knowledge = st.session_state.generated
359
- expertise = st.session_state.expertise
360
- rag_poems = st.session_state.rag
361
-
362
- # Convertir las listas en texto
363
- knowledge = '\n * '.join(knowledge)
364
- expertise = ' '.join(expertise)
365
- rag_poems = ' '.join(rag_poems)
366
-
367
- # Lanzamos la consulta
368
- chain = prompt | st.session_state.llm_creative | StrOutputParser()
369
- draft_poem = chain.invoke({"topic": topic, "knowledge": knowledge, "expertise": expertise, "rag_poems": rag_poems})
370
-
371
- # Valor global
372
- st.session_state.draft_poem = draft_poem
373
-
374
-
375
-
376
- # ----- Función para generar el poema final -------------------------------------------------
377
- def final_poem(poema, review):
378
-
379
- # Armamos el prompt
380
- system = """
381
- Eres un experto escritor de poesía que mejora los poemas. Tu objetivo es reescribir el poema proporcionado \
382
- a partir de los comentarios proporcionadas por el profesor experto. \
383
-
384
- POEMA:
385
- '''
386
- {poema}
387
- '''
388
-
389
- COMENTARIOS del profesor experto:
390
- '''
391
- * {review}
392
- '''
393
- """
394
- human=(
395
- "Escribe solo el poema final mejorado, el mejor posible. "
396
- "No hagas comentarios, ni aclaraciones sobre lo que has modificado. Esto es muy importante para mi carrera."
397
- )
398
-
399
- prompt = ChatPromptTemplate.from_messages([
400
- ("system", system),
401
- ("human", human),
402
- ])
403
-
404
- # Convertir las listas en texto
405
- review = '\n * '.join(list(review))
406
-
407
- # Lanzamos la consulta
408
- chain = prompt | st.session_state.llm_creative | StrOutputParser()
409
- final_poem = chain.invoke({"poema": poema, "review": review})
410
-
411
- # Valor global
412
- return final_poem
413
-
414
-
415
-
416
- # ----- Función para mostrar el conocimiento generado -------------------------------------
417
- def reflexion_catedratico():
418
-
419
- # Armamos el prompt
420
- system = """
421
- Eres un catedrático experto en poesía de una prestigiosa universidad con un profundo conocimiento y experiencia \
422
- en el análisis de poemas. Tienes ojo crítico y una pasión por la perfección literaria. Tu objetivo es revisar y \
423
- sugerir mejoras para los poemas.
424
-
425
- Evalúas y analizas la calidad del poema recibido y proporcionas comentarios constructivos que permitan mejorar el resultado final.
426
-
427
- Este es el poema:
428
- '''
429
- {draft_poem}
430
- '''
431
- """
432
- #Devuelve un listado detallado de las características en formato JSON con una única clave 'comentarios'.
433
- human = 'Devuelve SOLO un listado detallado de los comentarios en formato JSON. \
434
- Formato: {{ "comentarios": ["comentario 1", "comentario 2", "comentario 3"]}}'
435
-
436
- prompt = ChatPromptTemplate.from_messages([
437
- ("system", system),
438
- ("human", human),
439
- ])
440
-
441
- # Recupera los valores del grafo
442
- draft_poem = st.session_state.draft_poem
443
-
444
- # Lanzamos la consulta
445
- chain = prompt | st.session_state.llm | JsonOutputParser()
446
- reflexion = chain.invoke({"draft_poem": draft_poem})
447
-
448
- # Parser
449
- comentarios = list(reflexion.values())[0]
450
-
451
- # Valor global
452
- st.session_state.reflexion = comentarios
453
-
454
-
455
- # ----- Función para mostrar el conocimiento experto -------------------------------------
456
- def professor_reflexion():
457
- st.header(":female-student: Professor Reflexion (HITL)", divider='red')
458
-
459
- # Mostrar el texto combinado
460
- st.write("Poema")
461
- st.markdown(f"```\n{st.session_state.poema}\n```")
462
-
463
- # Valor global
464
- if st.session_state.poema != "No hay poema elaborado.":
465
-
466
- col1, col2 = st.columns(2)
467
- with col1:
468
- # Audio
469
- voz = st.button("Recitar", use_container_width=True, help="Recita el poema en alto")
470
- with col2:
471
- # Imagen
472
- imagen = st.button("Imaginar", use_container_width=True, help="Genera una imagen a partir del poema")
473
-
474
- if voz:
475
- try:
476
- # Generamos el audio
477
- audio = recitar(st.session_state.poema)
478
- st.audio(audio, format="audio/mp3")
479
- except Exception as e:
480
- # Manejo de la excepción
481
- st.error(f"No dispones de créditos suficientes para realizar esta operación.")
482
-
483
- if imagen:
484
- try:
485
- # Generamos la imagen
486
- url_imagen, enlace = pintar(st.session_state.draft_poem)
487
- # Mostrar la imagen
488
- st.image(url_imagen, use_column_width="always")
489
- st.markdown(enlace, unsafe_allow_html=True)
490
- except Exception as e:
491
- # Manejo de la excepción
492
- st.error(f"No dispones de créditos suficientes para realizar esta operación.")
493
-
494
-
495
- # Crear cuatro campos de textarea
496
- professor = st.text_area("Comentarios, crítica y sugerencias", help="Escribe aquí la revisión experta del catedrático.")
497
-
498
- # Reflexión
499
- if st.button("Escribir", type="primary", use_container_width=True):
500
- # Parser
501
- st.session_state.professor = [professor]
502
- st.session_state.expert_poem = st.session_state.poema
503
-
504
- with st.spinner("Reformando el poema..."):
505
- st.session_state.poema = final_poem(st.session_state.poema, professor)
506
- pass
507
- st.success("¡Poema reformado! :thumbsup:")
508
-
509
- # Almacenamos el poema en Supabase
510
- almacenar("update")
511
-
512
- # Mostramos el poema elaborado
513
- st.markdown(f"```{st.session_state.poema}```")
514
-
515
-
516
-
517
- # ----- Función para mostrar el resumen del poema generado ----------------------------------
518
- @st.cache_resource()
519
- def pintar(poema):
520
-
521
- # Lanzamos la consulta al modelo de lenguaje multimodal
522
- prompt = "Dibuja una imagen que represente de forma abstracta el siguiente poema. No incluyas NINGUN texto. No incluyas texto. POEMA:" + poema
523
- response = st.session_state.llm_images.images.generate(
524
- model="dall-e-3",
525
- prompt=prompt,
526
- size="1024x1024",
527
- quality="standard",
528
- n=1,
529
- )
530
-
531
- # Capturar el link
532
- url_imagen = response.data[0].url
533
-
534
- # Crear el enlace en Markdown
535
- link_text = "Haz clic aquí para ver la imagen en grande"
536
- link = f'[{link_text}]({url_imagen})'
537
-
538
- return url_imagen, link
539
-
540
-
541
-
542
- # ----- Función para mostrar el resumen del poema generado ----------------------------------
543
- @st.cache_resource()
544
- def recitar(poema):
545
-
546
- eleven_api_key = os.environ.get("ELEVEN_API_KEY")
547
-
548
- client = ElevenLabs(
549
- api_key=eleven_api_key,
550
- )
551
-
552
- audio = client.generate(
553
- text=poema,
554
- voice="Sara Martin 3",
555
- model="eleven_multilingual_v2"
556
- )
557
-
558
- audio_bytes = b''
559
- for chunk in audio:
560
- audio_bytes += chunk
561
-
562
- return audio_bytes
563
-
564
-
565
- # ----- Función para almacenar el registro en la base de datos ----------------------------
566
- def almacenar(accion):
567
-
568
- # Insertar los datos en la tabla
569
- data = {
570
- "model": st.session_state.modelo_llm,
571
- "temperature": st.session_state.temperature,
572
- "topic": st.session_state.tema,
573
- "style_of": st.session_state.estilo,
574
- "knowledge": st.session_state.generated,
575
- "expertise": st.session_state.expertise,
576
- "rag_poems": st.session_state.rag,
577
- "draft_poem": st.session_state.draft_poem,
578
- "draft_poem_fb": st.session_state.reflexion,
579
- "professor": st.session_state.professor,
580
- "final_poem": st.session_state.poema,
581
- }
582
-
583
- # Almacenamos los poemas generados
584
- if accion == "insert":
585
- # Añadimos registro
586
- data, count = st.session_state.supabase.table("Poemas").insert(data).execute()
587
- # Recuperamos el id insertado
588
- st.session_state.id = data[1][0]['id']
589
-
590
- if accion == "update":
591
- id = st.session_state.id
592
- data, count = st.session_state.supabase.table("Poemas").update(data).eq("id", id).execute()
593
-
594
-
595
-
596
- # ----- Función para mostrar el resumen del poema generado ----------------------------------
597
- def resumen():
598
-
599
- st.header(":memo: Metodología desarrollada", divider='gray')
600
-
601
- # Muestro el tema y estilo proporcionados
602
- col1, col2 = st.columns(2)
603
- with col1:
604
- input1 = st.text_input("Tema", value=st.session_state.tema, disabled=True)
605
- with col2:
606
- input2 = st.text_input("Estilo", value=st.session_state.estilo, disabled=True)
607
-
608
- # Separador
609
- st.subheader('Contexto', divider='red', help="Se muestra el *contexto* generado que se incrustará en el _prompt_")
610
-
611
- # Mostrar el conocimiento experto
612
- with st.expander("Expertise Knowledge (HITL)", icon="👩‍💻"):
613
- for item in st.session_state.expertise:
614
- st.markdown(f"```\n{item}\n```")
615
-
616
- # Imprimir la conocimiento generado
617
- with st.expander("Conocimiento generado", icon="💻"):
618
- for item in st.session_state.generated:
619
- st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
620
-
621
- # Imprimir la conocimiento recuperado
622
- with st.expander("Conocimiento recuperado", icon="💾"):
623
- for item in st.session_state.rag:
624
- st.markdown(f"```\n{item}\n```")
625
-
626
- # Separador
627
- st.subheader('Reflexión', divider='red', help="Se muestra el borrador poético y las reflexiones de los expertos")
628
-
629
- # Imprimir el borrador poético
630
- with st.expander("Borrador poético", icon="📃"):
631
- st.markdown(f"```\n{st.session_state.draft_poem}\n```")
632
-
633
- # Imprimir la reflexión del catedrático
634
- with st.expander("Reflexión del catedrático", icon="🎓"):
635
- for item in st.session_state.reflexion:
636
- st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
637
-
638
- # Imprimir el poema
639
- if "expert_poem" in st.session_state:
640
- with st.expander("Poema revisado", icon="📃"):
641
- st.markdown(f"```{st.session_state.expert_poem}```")
642
-
643
- # Imprimir la reflexión del catedrático
644
- if "professor" in st.session_state:
645
- with st.expander("Reflexión del profesor (HITL)", icon="👩‍🎓"):
646
- for item in st.session_state.professor:
647
- st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
648
-
649
- # Separador
650
- st.subheader('Poema :scroll:', divider='rainbow', help="Se muestra el poema elaborado")
651
-
652
- # Imprimir el poema
653
- st.markdown(f"```\n{st.session_state.poema}\n```")
654
-
655
-
656
-
657
- #####################
658
- # Función principal #
659
- #####################
660
- def main():
661
- st.set_page_config(page_title="Generador de poemas")
662
-
663
- if "draft_poem" not in st.session_state:
664
- st.session_state.draft_poem = "No hay borrador poético."
665
- #st.session_state.expert_poem = ""
666
- st.session_state.poema = "No hay poema elaborado."
667
- if "generated" not in st.session_state:
668
- st.session_state.generated = ["No hay conocimiento generado."]
669
- if "expertise" not in st.session_state:
670
- st.session_state.expertise = ["No hay conocimiento experto proporcionado."]
671
- if "rag" not in st.session_state:
672
- st.session_state.rag = ["No hay conocimiento aumentado por recuperación."]
673
- if "reflexion" not in st.session_state:
674
- st.session_state.reflexion = ["No hay revisiones del catedrático."]
675
- if "professor" not in st.session_state:
676
- st.session_state.professor = ["No hay revisiones del profesor."]
677
- if 'tema' not in st.session_state:
678
- st.session_state.tema = ""
679
- if 'estilo' not in st.session_state:
680
- st.session_state.estilo = ""
681
-
682
- # Ejecutamos la configuración
683
- __init__()
684
-
685
- # Sidebar con los enlaces a los pasos
686
- opciones = {
687
- "Topic&Style": grafo,
688
- "Metodología": resumen,
689
- "Expertise (HITL)": expertise_knowledge,
690
- "Professor (HITL)": professor_reflexion,
691
- "Configuración": configuracion,
692
- }
693
- #st.sidebar.title("Pasos")
694
- #selected = st.sidebar.radio("Selecciona un paso", list(opciones.keys()))
695
-
696
- # Enlace a la librería de menús: https://github.com/victoryhb/streamlit-option-menu
697
- with st.sidebar:
698
- seleccion = option_menu(None, list(opciones.keys()),
699
- icons=['envelope-paper-heart','envelope-heart','person-hearts','person-square', 'gear'],
700
- menu_icon="cast",
701
- default_index=0)
702
- st.image("img/bot.webp", width=250)
703
-
704
- # Muestra el paso seleccionado
705
- opciones[seleccion]()
706
-
707
-
708
- if __name__ == "__main__":
709
-
710
- main()
 
 
1
+ from langchain_groq import ChatGroq
2
+ from langchain_openai import ChatOpenAI
3
+ from langchain_community.embeddings import HuggingFaceEmbeddings
4
+ #from langchain.chains import RetrievalQA
5
+ from langchain_pinecone import PineconeVectorStore
6
+ from langchain_core.output_parsers import JsonOutputParser, StrOutputParser
7
+ from langchain_core.prompts import ChatPromptTemplate
8
+ from streamlit_option_menu import option_menu
9
+ #from elevenlabs import save, play, stream
10
+ from elevenlabs.client import ElevenLabs
11
+ from supabase import create_client, Client
12
+ from openai import OpenAI
13
+ from dotenv import load_dotenv
14
+
15
+ import os
16
+ import time
17
+ import streamlit as st
18
+
19
+
20
+
21
+ #####################
22
+ # CONFIGURACIÓN #
23
+ #####################
24
+
25
+ # Función de configuración de embedding
26
+ @st.cache_resource()
27
+ def load_embedding_model(model_name):
28
+ return HuggingFaceEmbeddings(model_name=model_name)
29
+
30
+ # Función de configuración
31
+ def configuracion():
32
+
33
+ # Cabecera
34
+ st.header(":gear: Configuración", divider='gray')
35
+
36
+ # API Keys #
37
+ hf_token = os.getenv('HF_TOKEN')
38
+ groq_api_key = os.getenv('GROQ_API_KEY')
39
+ openai_api_key = os.getenv('OPENAI_API_KEY')
40
+ pinecone_api_key = os.getenv('PINECONE_API_KEY')
41
+ supabase_key = os.getenv('SUPABASE_KEY')
42
+ supabase_url = os.getenv('SUPABASE_URL')
43
+ eleven_api_key = os.getenv('ELEVEN_API_KEY')
44
+ langsmith_api_key = os.getenv('LANGSMITH_API_KEY')
45
+ langchain_project = os.getenv('LANGCHAIN_PROJECT')
46
+ langchain_tracing_v2 = os.getenv('LANGCHAIN_TRACING_V2')
47
+
48
+ # Modelo de lenguaje #
49
+ modelos_llm = [
50
+ 'llama3-8b-8192',
51
+ 'llama3-70b-8192',
52
+ 'mixtral-8x7b-32768',
53
+ 'gemma-7b-it',
54
+ 'gpt-4o',
55
+ ]
56
+ modelo_llm = st.selectbox('Modelo de lenguaje', list(modelos_llm), help="Especifica el modelo de lenguaje utilizado")
57
+
58
+ # Temperatura
59
+ temperature = st.slider("Temperatura", 0.0, 2.0, 1.0, disabled=True, step=0.1)
60
+
61
+ if modelo_llm == "gpt-4o":
62
+ llm = ChatOpenAI(model=modelo_llm)
63
+ llm_creative = ChatOpenAI(model=modelo_llm, temperature=temperature)
64
+ else:
65
+ llm = ChatGroq(model=modelo_llm)
66
+ llm_creative = ChatGroq(model=modelo_llm, temperature=temperature)
67
+
68
+ # Embeddings #
69
+ model_name = 'intfloat/multilingual-e5-small'
70
+ model_name = st.text_input("Modelo de embedding:", value=model_name, disabled=True, help="Indica el modelo de _embedding_ utilizado en la vectorstore")
71
+ #embedding = HuggingFaceEmbeddings(model_name=model_name)
72
+ embedding = load_embedding_model(model_name)
73
+
74
+ # Pinecone #
75
+ index_name = "poemas-intfloat-multilingual-e5-small"
76
+ namespace = "poesiacastellana"
77
+ vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding)
78
+ col1, col2 = st.columns(2)
79
+ with col1:
80
+ input1 = st.text_input("Index", value=index_name, disabled=True, help="Nombre del _index_ del vectorstore en Pinecone para RAG")
81
+ with col2:
82
+ input2 = st.text_input("namespace", value=namespace, disabled=True, help="Nombre del _namespace_ del vectorstore en Pinecone")
83
+
84
+ # Supabase #
85
+ url: str = os.environ.get("SUPABASE_URL")
86
+ key: str = os.environ.get("SUPABASE_KEY")
87
+ supabase: Client = create_client(url, key)
88
+
89
+ # Variables globales
90
+ st.session_state.modelo_llm = modelo_llm
91
+ st.session_state.temperature = temperature
92
+ st.session_state.llm = llm
93
+ st.session_state.llm_creative = llm_creative
94
+ st.session_state.embedding = embedding
95
+ st.session_state.db = vectorstore
96
+ st.session_state.supabase = supabase
97
+
98
+ # API Keys #
99
+ with st.expander("API Keys"):
100
+ GROQ_API_KEY = st.text_input('Groq API Key', value=groq_api_key, type='password')
101
+ OPENAI_API_KEY = st.text_input('OpenAI API Key', value=openai_api_key, type='password')
102
+ HF_TOKEN = st.text_input('HuggingFace API Key', value=hf_token, type='password')
103
+ PINECONE_API_KEY = st.text_input('Pinecone API Key', value=pinecone_api_key, type='password')
104
+ ELEVEN_API_KEY = st.text_input('ElevenLabs API Key', value=eleven_api_key, type='password')
105
+
106
+
107
+
108
+ # ----- Función de configuración -----------------------------------------------------------
109
+ @st.cache_resource()
110
+ def __init__():
111
+
112
+ # API Keys #
113
+ load_dotenv()
114
+
115
+ # Modelo de lenguaje multimodal
116
+ llm_images = OpenAI()
117
+
118
+ # Modelo de lenguaje
119
+ modelo_llm = 'llama3-8b-8192'
120
+ temperature = 1
121
+ llm = ChatGroq(model=modelo_llm)
122
+ llm_creative = ChatGroq(model=modelo_llm, temperature=temperature)
123
+
124
+ # Embeddings
125
+ model_name = 'intfloat/multilingual-e5-small'
126
+ embedding = load_embedding_model(model_name)
127
+
128
+ # Pinecone
129
+ index_name = "poemas-intfloat-multilingual-e5-small"
130
+ namespace = "poesiacastellana"
131
+ vectorstore = PineconeVectorStore(index_name=index_name, namespace=namespace, embedding=embedding)
132
+
133
+ # Supabase
134
+ url: str = os.environ.get("SUPABASE_URL")
135
+ key: str = os.environ.get("SUPABASE_KEY")
136
+ supabase: Client = create_client(url, key)
137
+
138
+ # Globals
139
+ st.session_state.modelo_llm = modelo_llm
140
+ st.session_state.temperature = temperature
141
+ st.session_state.llm = llm
142
+ st.session_state.llm_creative = llm_creative
143
+ st.session_state.llm_images = llm_images
144
+ st.session_state.embedding = embedding
145
+ st.session_state.db = vectorstore
146
+ st.session_state.supabase = supabase
147
+
148
+
149
+ #####################
150
+ # GRAFO #
151
+ #####################
152
+
153
+ # ----- Función para desarrollar la metodología ------------------------------------------------
154
+ def grafo():
155
+
156
+ # Añadir una imagen al lado del título
157
+ col1, col2 = st.columns([4,20])
158
+ with col1:
159
+ st.image("img/bot.png", width=100)
160
+ with col2:
161
+ st.title("Generador de poemas")
162
+
163
+ # Botones de sugerencia para el tema/estilo
164
+ tema_suggestions = ["Amor", "Vida", "Misterio", "Aventura", "Sueños", "Amistad", "Impermanencia"]
165
+ estilo_suggestions = ["Romántico", "Gótico", "Épico", "Lírico", "Soneto", "Haiku", "Verso libre", "Gen27"]
166
+
167
+ # Campo para el tema
168
+ tema = st.text_input("Tema:", value="el despertar de la conciencia", help="Especifa el *tema* sobre el que quieres escribir el poema")
169
+ #tema_seleccionado = st.multiselect("Selecciona las opciones deseadas:", tema_suggestions)
170
+
171
+ # Campo para el estilo/estructura
172
+ estilo = st.text_input("Estilo:", value="antonio machado", help="Especifa el *estilo* con el que quieres escribir el poema")
173
+ #estilo_seleccionado = st.multiselect("Selecciona las opciones deseadas:", estilo_suggestions)
174
+
175
+ # Mostrar el conocimiento experto
176
+ with st.expander("Expertise Knowledge", icon="👩‍💻"):
177
+ for item in st.session_state.expertise:
178
+ st.markdown(f"```\n{item}\n```")
179
+
180
+ # Botón para generar el poema
181
+ if st.button("Generar Poema", type="primary", use_container_width=True):
182
+
183
+ # Variables globales
184
+ st.session_state.tema = tema
185
+ st.session_state.estilo = estilo
186
+ st.session_state.professor = ["No hay revisiones del profesor."]
187
+
188
+ # Generación del contexto
189
+ with st.spinner("Recuperando conocimiento aumentado..."):
190
+ rag_retrieval()
191
+ pass
192
+ st.success(":floppy_disk: ¡Conocimiento aumentado recuperado!")
193
+
194
+ # Generación del conocimiento
195
+ with st.spinner("Generando conocimiento experto..."):
196
+ generated_knowledge()
197
+ pass
198
+ st.success(":notebook: ¡Conocimiento experto generado!")
199
+
200
+ # Generación del borrador poético
201
+ with st.spinner("Generando borrador poético..."):
202
+ draft_poem()
203
+ pass
204
+ st.success(":memo: ¡Borrador poético generado!")
205
+
206
+ # Generando reflexion
207
+ with st.spinner("El catedrático está revisando el borrador poético..."):
208
+ reflexion_catedratico()
209
+ pass
210
+ st.success(":female-student: ¡Borrador poético revisado!")
211
+
212
+ # Generando poema
213
+ with st.spinner("Generando el poema..."):
214
+ st.session_state.poema = final_poem(st.session_state.draft_poem, st.session_state.reflexion)
215
+ pass
216
+ st.success(":scroll: ¡Poema generado!")
217
+
218
+ # Almacenar poema en Supabase
219
+ almacenar("insert")
220
+
221
+ # Mostrar poema
222
+ st.markdown(f"```\n{st.session_state.poema}\n```")
223
+
224
+
225
+ #####################
226
+ # AGENTES #
227
+ #####################
228
+
229
+ # ----- Función para mostrar la recuperación aumentada -----------------------------------
230
+ def rag_retrieval():
231
+
232
+ # Define the filter condition based on the 'author' metadata field
233
+ filter = {}
234
+
235
+ # Define el número de resultados
236
+ k=20
237
+
238
+ # Recupera los valores del grafo
239
+ tema = st.session_state.tema
240
+
241
+ # Perform the search: topic, human
242
+ documents = st.session_state.db.similarity_search(tema, k=k, filter=filter) #db.similarity_search_with_score
243
+
244
+ # Armamos la lista
245
+ rag_poems = [doc.page_content for doc in documents]
246
+
247
+ # Variable global
248
+ st.session_state.rag = rag_poems
249
+
250
+
251
+ # ----- Función para mostrar el conocimiento experto -------------------------------------
252
+ def expertise_knowledge():
253
+
254
+ # Mostramos una cabecera
255
+ st.header(":female-technologist: Expertise Knowledge (HITL)", divider='red')
256
+
257
+ # Campo de texto para ingresar poemas
258
+ 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.")
259
+
260
+ # Botones para añadir y actualizar
261
+ col1, col2 = st.columns(2, gap="small")
262
+ with col1:
263
+ if st.button("Añadir", use_container_width=True):
264
+ st.session_state.expertise.insert(0, f"Poema:\n{poema.strip()}")
265
+ poema = "" # Limpiar el campo poema
266
+ with col2:
267
+ if st.button("Actualizar", type="primary", use_container_width=True):
268
+ st.session_state.expertise = [f"Poema:\n{poema.strip()}"]
269
+ poema = "" # Limpiar el campo poema
270
+
271
+ # Mostrar el conocimiento experto
272
+ st.divider()
273
+ #st.write("Expertise Knowledge:")
274
+ for poem in st.session_state.expertise:
275
+ st.markdown(f"```\n{poem}\n```")
276
+
277
+
278
+ # ----- Función para mostrar el conocimiento generado -------------------------------------
279
+ def generated_knowledge():
280
+
281
+ # Armamos el prompt
282
+ system = """
283
+ Eres un ratón de biblioteca y un profesor experto de literatura de una prestigiosa universidad con gran capacidad de \
284
+ sintetizar características de corrientes y estilos literarios. Tu objetivo es proporcionar las características principales \
285
+ y los detalles de las consultas académicas que te hagan sobre el estilo poético de '''{style_of}'''. Escribe las \
286
+ características principales sobre el estilo literario, movimiento o generación definido en el estilo o en el poeta nombrado, \
287
+ que sirvan de guía para la elaboración de nuevos textos que imiten el estilo indicado o al poeta solicitado.
288
+
289
+ Es importante que no escribas ningún poema, tan solo enumera un listado detallado de características, que sean útiles \
290
+ para poder reproducirse y aplicarse en la generación de nuevos textos.
291
+ """
292
+ human = 'Devuelve SOLO un listado detallado de las características en formato JSON. \
293
+ Formato: {{ "Características": ["característica 1", "característica 2", "característica 3"]}}'
294
+
295
+ prompt = ChatPromptTemplate.from_messages([
296
+ ("system", system),
297
+ ("human", human),
298
+ ])
299
+
300
+ # Recupera los valores del grafo
301
+ style_of = st.session_state.estilo
302
+
303
+ # Lanzamos la consulta
304
+ chain = prompt | st.session_state.llm | JsonOutputParser()
305
+ knowledge = chain.invoke({"style_of": style_of})
306
+
307
+ # Parser
308
+ knowledge_values = list(knowledge.values())[0]
309
+
310
+ # Valor global
311
+ st.session_state.generated = knowledge_values
312
+
313
+
314
+ # ----- Función para generar el borrado poético------ -------------------------------------
315
+ def draft_poem():
316
+
317
+ # Armamos el prompt
318
+ system = """
319
+ Eres un maestro de la poesía, capaz de escribir poemas que evocan emociones poderosas y obras maestras poéticas \
320
+ que capten la esencia del tema especificado de forma profunda y evocadora. Escribes desde la belleza. Cada línea \
321
+ cuidadosamente elaborada proyecta una imagen vívida, evocando emociones fuertes y hermosas con una destreza poética \
322
+ que deja sin aliento al lector. Tu estilo es una fusión de metáforas, aliteración y cadencia rítmica.
323
+
324
+ Las imágenes que evocan tus palabras son originales, creativas y únicas, alejándose de los tópicos y dotadas de un \
325
+ significado profundo y auténtico. Tus poemas están escritos para recitarse y leerse en voz alta. Se hace hincapié en \
326
+ que la escritura sea vívida y detallada, al tiempo que se garantiza que los poemas tengan un mensaje profundo que \
327
+ resuene en el lector mucho después de que haya terminado de leerlos. El objetivo es crear una poesía impactante y \
328
+ bella que deje una impresión duradera en el público.
329
+
330
+ Haces un uso de la rima es muy sutil, SOLO la utilizas cuando es necesaria. Si las características proporcionadas no \
331
+ indican lo contrario, haz un uso responsable y limitado de ella.
332
+
333
+ Esta es una lista de poemas que debes utilizar como EJEMPLOS e inspiración para escribir el poema:
334
+ '''{expertise}'''
335
+
336
+ Aquí tienes una lista de poemas con una temática similar que puedes usar para inspirarte:
337
+ '''
338
+ {rag_poems}
339
+ '''
340
+ """
341
+ human = (
342
+ "El poema debe escribirse atendiendo a las siguientes CARACTERÍSTICAS: "
343
+ "\n'''"
344
+ "\n * 18 versos o menos, no debes superar NUNCA esta cantidad "
345
+ "\n * {knowledge} "
346
+ "\n''' "
347
+ "\n\nEscribe un BREVE poema de menos de 18 versos sobre el tema de '''{topic}'''. "
348
+ "No hagas comentarios. " + "Esto es muy importante para mi carrera."
349
+ )
350
+
351
+ prompt = ChatPromptTemplate.from_messages([
352
+ ("system", system),
353
+ ("human", human),
354
+ ])
355
+
356
+ # Recupera los valores del grafo
357
+ topic = st.session_state.tema
358
+ knowledge = st.session_state.generated
359
+ expertise = st.session_state.expertise
360
+ rag_poems = st.session_state.rag
361
+
362
+ # Convertir las listas en texto
363
+ knowledge = '\n * '.join(knowledge)
364
+ expertise = ' '.join(expertise)
365
+ rag_poems = ' '.join(rag_poems)
366
+
367
+ # Lanzamos la consulta
368
+ chain = prompt | st.session_state.llm_creative | StrOutputParser()
369
+ draft_poem = chain.invoke({"topic": topic, "knowledge": knowledge, "expertise": expertise, "rag_poems": rag_poems})
370
+
371
+ # Valor global
372
+ st.session_state.draft_poem = draft_poem
373
+
374
+
375
+
376
+ # ----- Función para generar el poema final -------------------------------------------------
377
+ def final_poem(poema, review):
378
+
379
+ # Armamos el prompt
380
+ system = """
381
+ Eres un experto escritor de poesía que mejora los poemas. Tu objetivo es reescribir el poema proporcionado \
382
+ a partir de los comentarios proporcionadas por el profesor experto. \
383
+
384
+ POEMA:
385
+ '''
386
+ {poema}
387
+ '''
388
+
389
+ COMENTARIOS del profesor experto:
390
+ '''
391
+ * {review}
392
+ '''
393
+ """
394
+ human=(
395
+ "Escribe solo el poema final mejorado, el mejor posible. "
396
+ "No hagas comentarios, ni aclaraciones sobre lo que has modificado. Esto es muy importante para mi carrera."
397
+ )
398
+
399
+ prompt = ChatPromptTemplate.from_messages([
400
+ ("system", system),
401
+ ("human", human),
402
+ ])
403
+
404
+ # Convertir las listas en texto
405
+ review = '\n * '.join(list(review))
406
+
407
+ # Lanzamos la consulta
408
+ chain = prompt | st.session_state.llm_creative | StrOutputParser()
409
+ final_poem = chain.invoke({"poema": poema, "review": review})
410
+
411
+ # Valor global
412
+ return final_poem
413
+
414
+
415
+
416
+ # ----- Función para mostrar el conocimiento generado -------------------------------------
417
+ def reflexion_catedratico():
418
+
419
+ # Armamos el prompt
420
+ system = """
421
+ Eres un catedrático experto en poesía de una prestigiosa universidad con un profundo conocimiento y experiencia \
422
+ en el análisis de poemas. Tienes ojo crítico y una pasión por la perfección literaria. Tu objetivo es revisar y \
423
+ sugerir mejoras para los poemas.
424
+
425
+ Evalúas y analizas la calidad del poema recibido y proporcionas comentarios constructivos que permitan mejorar el resultado final.
426
+
427
+ Este es el poema:
428
+ '''
429
+ {draft_poem}
430
+ '''
431
+ """
432
+ #Devuelve un listado detallado de las características en formato JSON con una única clave 'comentarios'.
433
+ human = 'Devuelve SOLO un listado detallado de los comentarios en formato JSON. \
434
+ Formato: {{ "comentarios": ["comentario 1", "comentario 2", "comentario 3"]}}'
435
+
436
+ prompt = ChatPromptTemplate.from_messages([
437
+ ("system", system),
438
+ ("human", human),
439
+ ])
440
+
441
+ # Recupera los valores del grafo
442
+ draft_poem = st.session_state.draft_poem
443
+
444
+ # Lanzamos la consulta
445
+ chain = prompt | st.session_state.llm | JsonOutputParser()
446
+ reflexion = chain.invoke({"draft_poem": draft_poem})
447
+
448
+ # Parser
449
+ comentarios = list(reflexion.values())[0]
450
+
451
+ # Valor global
452
+ st.session_state.reflexion = comentarios
453
+
454
+
455
+ # ----- Función para mostrar el conocimiento experto -------------------------------------
456
+ def professor_reflexion():
457
+ st.header(":female-student: Professor Reflexion (HITL)", divider='red')
458
+
459
+ # Mostrar el texto combinado
460
+ st.write("Poema")
461
+ st.markdown(f"```\n{st.session_state.poema}\n```")
462
+
463
+ # Valor global
464
+ if st.session_state.poema != "No hay poema elaborado.":
465
+
466
+ col1, col2 = st.columns(2)
467
+ with col1:
468
+ # Audio
469
+ voz = st.button("Recitar", use_container_width=True, help="Recita el poema en alto")
470
+ with col2:
471
+ # Imagen
472
+ imagen = st.button("Imaginar", use_container_width=True, help="Genera una imagen a partir del poema")
473
+
474
+ if voz:
475
+ try:
476
+ # Generamos el audio
477
+ audio = recitar(st.session_state.poema)
478
+ st.audio(audio, format="audio/mp3")
479
+ except Exception as e:
480
+ # Manejo de la excepción
481
+ st.error(f"No dispones de créditos suficientes para realizar esta operación.")
482
+
483
+ if imagen:
484
+ try:
485
+ # Generamos la imagen
486
+ url_imagen, enlace = pintar(st.session_state.draft_poem)
487
+ # Mostrar la imagen
488
+ st.image(url_imagen, use_column_width="always")
489
+ st.markdown(enlace, unsafe_allow_html=True)
490
+ except Exception as e:
491
+ # Manejo de la excepción
492
+ st.error(f"No dispones de créditos suficientes para realizar esta operación.")
493
+
494
+
495
+ # Crear cuatro campos de textarea
496
+ professor = st.text_area("Comentarios, crítica y sugerencias", help="Escribe aquí la revisión experta del catedrático.")
497
+
498
+ # Reflexión
499
+ if st.button("Escribir", type="primary", use_container_width=True):
500
+ # Parser
501
+ st.session_state.professor = [professor]
502
+ st.session_state.expert_poem = st.session_state.poema
503
+
504
+ with st.spinner("Reformando el poema..."):
505
+ st.session_state.poema = final_poem(st.session_state.poema, professor)
506
+ pass
507
+ st.success("¡Poema reformado! :thumbsup:")
508
+
509
+ # Almacenamos el poema en Supabase
510
+ almacenar("update")
511
+
512
+ # Mostramos el poema elaborado
513
+ st.markdown(f"```{st.session_state.poema}```")
514
+
515
+
516
+
517
+ # ----- Función para mostrar el resumen del poema generado ----------------------------------
518
+ @st.cache_resource()
519
+ def pintar(poema):
520
+
521
+ # Lanzamos la consulta al modelo de lenguaje multimodal
522
+ prompt = "Dibuja una imagen que represente de forma abstracta el siguiente poema. No incluyas NINGUN texto. No incluyas texto. POEMA:" + poema
523
+ response = st.session_state.llm_images.images.generate(
524
+ model="dall-e-3",
525
+ prompt=prompt,
526
+ size="1024x1024",
527
+ quality="standard",
528
+ n=1,
529
+ )
530
+
531
+ # Capturar el link
532
+ url_imagen = response.data[0].url
533
+
534
+ # Crear el enlace en Markdown
535
+ link_text = "Haz clic aquí para ver la imagen en grande"
536
+ link = f'[{link_text}]({url_imagen})'
537
+
538
+ return url_imagen, link
539
+
540
+
541
+
542
+ # ----- Función para mostrar el resumen del poema generado ----------------------------------
543
+ @st.cache_resource()
544
+ def recitar(poema):
545
+
546
+ eleven_api_key = os.environ.get("ELEVEN_API_KEY")
547
+
548
+ client = ElevenLabs(
549
+ api_key=eleven_api_key,
550
+ )
551
+
552
+ audio = client.generate(
553
+ text=poema,
554
+ voice="Sara Martin 3",
555
+ model="eleven_multilingual_v2"
556
+ )
557
+
558
+ audio_bytes = b''
559
+ for chunk in audio:
560
+ audio_bytes += chunk
561
+
562
+ return audio_bytes
563
+
564
+
565
+ # ----- Función para almacenar el registro en la base de datos ----------------------------
566
+ def almacenar(accion):
567
+
568
+ # Insertar los datos en la tabla
569
+ data = {
570
+ "model": st.session_state.modelo_llm,
571
+ "temperature": st.session_state.temperature,
572
+ "topic": st.session_state.tema,
573
+ "style_of": st.session_state.estilo,
574
+ "knowledge": st.session_state.generated,
575
+ "expertise": st.session_state.expertise,
576
+ "rag_poems": st.session_state.rag,
577
+ "draft_poem": st.session_state.draft_poem,
578
+ "draft_poem_fb": st.session_state.reflexion,
579
+ "professor": st.session_state.professor,
580
+ "final_poem": st.session_state.poema,
581
+ }
582
+
583
+ # Almacenamos los poemas generados
584
+ if accion == "insert":
585
+ # Añadimos registro
586
+ data, count = st.session_state.supabase.table("Poemas").insert(data).execute()
587
+ # Recuperamos el id insertado
588
+ st.session_state.id = data[1][0]['id']
589
+
590
+ if accion == "update":
591
+ id = st.session_state.id
592
+ data, count = st.session_state.supabase.table("Poemas").update(data).eq("id", id).execute()
593
+
594
+
595
+
596
+ # ----- Función para mostrar el resumen del poema generado ----------------------------------
597
+ def resumen():
598
+
599
+ st.header(":memo: Metodología desarrollada", divider='gray')
600
+
601
+ # Muestro el tema y estilo proporcionados
602
+ col1, col2 = st.columns(2)
603
+ with col1:
604
+ input1 = st.text_input("Tema", value=st.session_state.tema, disabled=True)
605
+ with col2:
606
+ input2 = st.text_input("Estilo", value=st.session_state.estilo, disabled=True)
607
+
608
+ # Separador
609
+ st.subheader('Contexto', divider='red', help="Se muestra el *contexto* generado que se incrustará en el _prompt_")
610
+
611
+ # Mostrar el conocimiento experto
612
+ with st.expander("Expertise Knowledge (HITL)", icon="👩‍💻"):
613
+ for item in st.session_state.expertise:
614
+ st.markdown(f"```\n{item}\n```")
615
+
616
+ # Imprimir la conocimiento generado
617
+ with st.expander("Conocimiento generado", icon="💻"):
618
+ for item in st.session_state.generated:
619
+ st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
620
+
621
+ # Imprimir la conocimiento recuperado
622
+ with st.expander("Conocimiento recuperado", icon="💾"):
623
+ for item in st.session_state.rag:
624
+ st.markdown(f"```\n{item}\n```")
625
+
626
+ # Separador
627
+ st.subheader('Reflexión', divider='red', help="Se muestra el borrador poético y las reflexiones de los expertos")
628
+
629
+ # Imprimir el borrador poético
630
+ with st.expander("Borrador poético", icon="📃"):
631
+ st.markdown(f"```\n{st.session_state.draft_poem}\n```")
632
+
633
+ # Imprimir la reflexión del catedrático
634
+ with st.expander("Reflexión del catedrático", icon="🎓"):
635
+ for item in st.session_state.reflexion:
636
+ st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
637
+
638
+ # Imprimir el poema
639
+ if "expert_poem" in st.session_state:
640
+ with st.expander("Poema revisado", icon="📃"):
641
+ st.markdown(f"```{st.session_state.expert_poem}```")
642
+
643
+ # Imprimir la reflexión del catedrático
644
+ if "professor" in st.session_state:
645
+ with st.expander("Reflexión del profesor (HITL)", icon="👩‍🎓"):
646
+ for item in st.session_state.professor:
647
+ st.markdown(f"""<span>{item}</span>""", unsafe_allow_html=True)
648
+
649
+ # Separador
650
+ st.subheader('Poema :scroll:', divider='rainbow', help="Se muestra el poema elaborado")
651
+
652
+ # Imprimir el poema
653
+ st.markdown(f"```\n{st.session_state.poema}\n```")
654
+
655
+
656
+
657
+ #####################
658
+ # Función principal #
659
+ #####################
660
+ def main():
661
+ st.set_page_config(page_title="Generador de poemas")
662
+
663
+ if "draft_poem" not in st.session_state:
664
+ st.session_state.draft_poem = "No hay borrador poético."
665
+ #st.session_state.expert_poem = ""
666
+ #st.session_state.poema = "No hay poema elaborado."
667
+ st.session_state.poema = st.__version__
668
+ if "generated" not in st.session_state:
669
+ st.session_state.generated = ["No hay conocimiento generado."]
670
+ if "expertise" not in st.session_state:
671
+ st.session_state.expertise = ["No hay conocimiento experto proporcionado."]
672
+ if "rag" not in st.session_state:
673
+ st.session_state.rag = ["No hay conocimiento aumentado por recuperación."]
674
+ if "reflexion" not in st.session_state:
675
+ st.session_state.reflexion = ["No hay revisiones del catedrático."]
676
+ if "professor" not in st.session_state:
677
+ st.session_state.professor = ["No hay revisiones del profesor."]
678
+ if 'tema' not in st.session_state:
679
+ st.session_state.tema = ""
680
+ if 'estilo' not in st.session_state:
681
+ st.session_state.estilo = ""
682
+
683
+ # Ejecutamos la configuración
684
+ __init__()
685
+
686
+ # Sidebar con los enlaces a los pasos
687
+ opciones = {
688
+ "Topic&Style": grafo,
689
+ "Metodología": resumen,
690
+ "Expertise (HITL)": expertise_knowledge,
691
+ "Professor (HITL)": professor_reflexion,
692
+ "Configuración": configuracion,
693
+ }
694
+ #st.sidebar.title("Pasos")
695
+ #selected = st.sidebar.radio("Selecciona un paso", list(opciones.keys()))
696
+
697
+ # Enlace a la librería de menús: https://github.com/victoryhb/streamlit-option-menu
698
+ with st.sidebar:
699
+ seleccion = option_menu(None, list(opciones.keys()),
700
+ icons=['envelope-paper-heart','envelope-heart','person-hearts','person-square', 'gear'],
701
+ menu_icon="cast",
702
+ default_index=0)
703
+ st.image("img/bot.webp", width=250)
704
+
705
+ # Muestra el paso seleccionado
706
+ opciones[seleccion]()
707
+
708
+
709
+ if __name__ == "__main__":
710
+
711
+ main()