JairoCesar commited on
Commit
55ddbe9
·
verified ·
1 Parent(s): 252113a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -51
app.py CHANGED
@@ -1,19 +1,20 @@
1
  import streamlit as st
2
  from pptx import Presentation
3
  from pptx.util import Inches
4
- import io
 
 
 
5
  import json
6
  import re
7
- import os
8
- import google.generativeai as genai
9
 
10
- # Configurar Gemini
11
- GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") # Asegúrate de que esté bien escrito
12
- genai.configure(api_key=GEMINI_API_KEY)
13
 
14
  @st.cache_resource
15
- def get_gemini_model():
16
- return genai.GenerativeModel("gemini-1.5-flash") # Puedes cambiar al modelo que desees
17
 
18
  def extract_and_clean_json(text):
19
  json_match = re.search(r'\{.*\}', text, re.DOTALL)
@@ -25,101 +26,142 @@ def extract_and_clean_json(text):
25
  return json_str
26
  return None
27
 
28
- def generate_presentation_content(topic, model, max_retries=3):
29
  prompt = f"""Genera una presentación de PowerPoint sobre el tema: "{topic}".
30
- Debes crear exactamente 9 diapositivas. Cada diapositiva debe tener un título y contenido.
31
- La respuesta debe ser SOLO un JSON válido con la estructura:
32
-
33
- {{
34
- "slides": [
35
- {{"title": "Título 1", "content": "Contenido 1"}},
36
- ...
37
- {{"title": "Título 9", "content": "Contenido 9"}}
38
- ]
39
- }}"""
40
-
 
 
 
 
 
 
 
 
 
41
  for attempt in range(max_retries):
42
- response = model.generate_content(prompt)
43
-
44
  try:
45
- json_str = extract_and_clean_json(response.text)
46
  if json_str:
47
  slides_data = json.loads(json_str)
48
  if 'slides' in slides_data and len(slides_data['slides']) == 9:
49
  return slides_data['slides']
 
 
50
  raise ValueError("JSON inválido o estructura incorrecta")
 
51
  except (json.JSONDecodeError, ValueError) as e:
52
- if attempt == max_retries - 1:
53
- st.error(f"Error después de {max_retries} intentos: {str(e)}")
54
  st.text("Última respuesta del modelo:")
55
- st.code(response.text)
56
  return None
57
  else:
58
  st.warning(f"Intento {attempt + 1} fallido. Reintentando...")
 
 
 
 
 
 
 
59
 
 
 
 
 
60
  return None
61
 
62
  def create_powerpoint(slides, template_path):
63
  prs = Presentation(template_path)
 
64
  for slide_data in slides:
65
  slide = prs.slides.add_slide(prs.slide_layouts[1])
66
- if slide.shapes.title:
67
- slide.shapes.title.text = slide_data['title']
68
- if len(slide.placeholders) > 1:
69
- slide.placeholders[1].text = slide_data['content']
 
 
 
70
  else:
71
- textbox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(9), Inches(5))
72
- textbox.text_frame.text = slide_data['content']
 
73
 
 
 
 
 
 
 
 
 
 
 
 
74
  final_slide = prs.slides.add_slide(prs.slide_layouts[1])
75
- if final_slide.shapes.title:
76
- final_slide.shapes.title.text = "Gracias"
77
-
78
  pptx_buffer = io.BytesIO()
79
  prs.save(pptx_buffer)
80
  pptx_buffer.seek(0)
81
  return pptx_buffer
82
 
83
  def main():
84
- st.title("PowerPoint Mágico con GEMINI")
85
-
86
- model = get_gemini_model()
 
87
  topic = st.text_input("Por favor, ingrese el tema de la presentación:")
88
-
 
89
  template_options = {
90
  "Simple": "PLANTILLAS/Simple.pptx",
91
  "Corporativo": "PLANTILLAS/Corporativo.pptx",
92
  "Moderno": "PLANTILLAS/Moderno.pptx"
93
  }
94
-
95
  selected_template = st.selectbox("Seleccione una plantilla", list(template_options.keys()))
96
-
97
  if st.button("Generar Presentación"):
98
  if topic:
99
  try:
100
- with st.spinner("Generando contenido..."):
101
- slides = generate_presentation_content(topic, model)
102
-
103
  if slides:
104
  template_path = template_options[selected_template]
105
  if not os.path.exists(template_path):
106
  st.error(f"No se encontró la plantilla: {template_path}")
107
  return
108
-
109
- with st.spinner("Creando PowerPoint..."):
110
  pptx_buffer = create_powerpoint(slides, template_path)
111
-
112
- st.success("¡Presentación generada!")
 
113
  st.download_button(
114
  label="Descargar Presentación",
115
  data=pptx_buffer,
116
- file_name=f"{topic.replace(' ', '_')}_{selected_template}.pptx",
117
  mime="application/vnd.openxmlformats-officedocument.presentationml.presentation"
118
  )
119
  except Exception as e:
120
- st.error(f"Ocurrió un error: {str(e)}")
121
  else:
122
- st.warning("Por favor, ingrese un tema.")
123
 
124
  if __name__ == "__main__":
125
  main()
 
1
  import streamlit as st
2
  from pptx import Presentation
3
  from pptx.util import Inches
4
+ import requests
5
+ from PIL import Image
6
+ from io import BytesIO
7
+ import os
8
  import json
9
  import re
10
+ from huggingface_hub import InferenceClient
 
11
 
12
+ # Obtener la clave API de Pixabay desde los secretos de Streamlit
13
+ PIXABAY_API_KEY = st.secrets["pixabay"]["api_key"]
 
14
 
15
  @st.cache_resource
16
+ def get_inference_client():
17
+ return InferenceClient("gemini-2.0-flash")
18
 
19
  def extract_and_clean_json(text):
20
  json_match = re.search(r'\{.*\}', text, re.DOTALL)
 
26
  return json_str
27
  return None
28
 
29
+ def generate_presentation_content(topic, client, max_retries=3):
30
  prompt = f"""Genera una presentación de PowerPoint sobre el tema: "{topic}".
31
+ Debes crear exactamente 9 diapositivas. Cada diapositiva debe tener un título y contenido.
32
+ Es CRUCIAL que tu respuesta sea ÚNICAMENTE un JSON válido con la siguiente estructura exacta, sin texto adicional antes o después:
33
+
34
+ {{
35
+ "slides": [
36
+ {{"title": "Título de la diapositiva 1", "content": "Contenido de la diapositiva 1"}},
37
+ {{"title": "Título de la diapositiva 2", "content": "Contenido de la diapositiva 2"}},
38
+ {{"title": "Título de la diapositiva 3", "content": "Contenido de la diapositiva 3"}},
39
+ {{"title": "Título de la diapositiva 4", "content": "Contenido de la diapositiva 4"}},
40
+ {{"title": "Título de la diapositiva 5", "content": "Contenido de la diapositiva 5"}},
41
+ {{"title": "Título de la diapositiva 6", "content": "Contenido de la diapositiva 6"}},
42
+ {{"title": "Título de la diapositiva 7", "content": "Contenido de la diapositiva 7"}},
43
+ {{"title": "Título de la diapositiva 8", "content": "Contenido de la diapositiva 8"}},
44
+ {{"title": "Título de la diapositiva 9", "content": "Contenido de la diapositiva 9"}}
45
+ ]
46
+ }}
47
+
48
+ No incluyas ningún otro texto, explicación o saludo. Solo el JSON.
49
+ """
50
+
51
  for attempt in range(max_retries):
52
+ response = client.text_generation(prompt, max_new_tokens=2000, temperature=0.7)
53
+
54
  try:
55
+ json_str = extract_and_clean_json(response)
56
  if json_str:
57
  slides_data = json.loads(json_str)
58
  if 'slides' in slides_data and len(slides_data['slides']) == 9:
59
  return slides_data['slides']
60
+
61
+ # Si llegamos aquí, el JSON no era válido o no tenía la estructura correcta
62
  raise ValueError("JSON inválido o estructura incorrecta")
63
+
64
  except (json.JSONDecodeError, ValueError) as e:
65
+ if attempt == max_retries - 1: # Último intento
66
+ st.error(f"Error al generar el contenido después de {max_retries} intentos: {str(e)}")
67
  st.text("Última respuesta del modelo:")
68
+ st.code(response)
69
  return None
70
  else:
71
  st.warning(f"Intento {attempt + 1} fallido. Reintentando...")
72
+
73
+ return None
74
+
75
+ def buscar_imagen_pixabay(query):
76
+ url = f"https://pixabay.com/api/?key={PIXABAY_API_KEY}&q={requests.utils.quote(query)}&image_type=photo&per_page=10"
77
+ response = requests.get(url)
78
+ data = response.json()
79
 
80
+ if data.get('hits'):
81
+ image_url = data['hits'][0]['webformatURL']
82
+ image_response = requests.get(image_url)
83
+ return Image.open(BytesIO(image_response.content))
84
  return None
85
 
86
  def create_powerpoint(slides, template_path):
87
  prs = Presentation(template_path)
88
+
89
  for slide_data in slides:
90
  slide = prs.slides.add_slide(prs.slide_layouts[1])
91
+ title_shape = slide.shapes.title
92
+ content_shape = slide.placeholders[1] if len(slide.placeholders) > 1 else None
93
+
94
+ if title_shape:
95
+ title_shape.text = slide_data['title']
96
+ if content_shape:
97
+ content_shape.text = slide_data['content']
98
  else:
99
+ txBox = slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(9), Inches(5))
100
+ tf = txBox.text_frame
101
+ tf.text = slide_data['content']
102
 
103
+ # Buscar e insertar imagen
104
+ try:
105
+ img = buscar_imagen_pixabay(slide_data['title']) # usar el título como consulta
106
+ if img:
107
+ img_path = "/tmp/temp_img.jpg"
108
+ img.save(img_path)
109
+ slide.shapes.add_picture(img_path, Inches(5), Inches(1.5), width=Inches(4))
110
+ except Exception as e:
111
+ print(f"No se pudo insertar imagen: {e}")
112
+
113
+ # Agregar diapositiva final
114
  final_slide = prs.slides.add_slide(prs.slide_layouts[1])
115
+ final_slide.shapes.title.text = "Gracias"
116
+
 
117
  pptx_buffer = io.BytesIO()
118
  prs.save(pptx_buffer)
119
  pptx_buffer.seek(0)
120
  return pptx_buffer
121
 
122
  def main():
123
+ st.title("PowerPoint Mágico con el Buho")
124
+
125
+ client = get_inference_client()
126
+
127
  topic = st.text_input("Por favor, ingrese el tema de la presentación:")
128
+
129
+ # Opciones de plantillas
130
  template_options = {
131
  "Simple": "PLANTILLAS/Simple.pptx",
132
  "Corporativo": "PLANTILLAS/Corporativo.pptx",
133
  "Moderno": "PLANTILLAS/Moderno.pptx"
134
  }
135
+
136
  selected_template = st.selectbox("Seleccione una plantilla", list(template_options.keys()))
137
+
138
  if st.button("Generar Presentación"):
139
  if topic:
140
  try:
141
+ with st.spinner("Generando contenido de la presentación..."):
142
+ slides = generate_presentation_content(topic, client)
143
+
144
  if slides:
145
  template_path = template_options[selected_template]
146
  if not os.path.exists(template_path):
147
  st.error(f"No se encontró la plantilla: {template_path}")
148
  return
149
+
150
+ with st.spinner("Creando archivo PowerPoint..."):
151
  pptx_buffer = create_powerpoint(slides, template_path)
152
+
153
+ st.success("Presentación generada con éxito!")
154
+
155
  st.download_button(
156
  label="Descargar Presentación",
157
  data=pptx_buffer,
158
+ file_name=f"{topic.replace(' ', '_')}_{selected_template}_presentacion.pptx",
159
  mime="application/vnd.openxmlformats-officedocument.presentationml.presentation"
160
  )
161
  except Exception as e:
162
+ st.error(f"Ocurrió un error al generar la presentación: {str(e)}")
163
  else:
164
+ st.warning("Por favor, ingrese un tema para la presentación.")
165
 
166
  if __name__ == "__main__":
167
  main()