JeCabrera commited on
Commit
6a1e884
·
verified ·
1 Parent(s): 4261c4f

Upload 13 files

Browse files
.gitattributes CHANGED
@@ -1,35 +1,36 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ docs/gemini-chatbot.gif filter=lfs diff=lfs merge=lfs -text
.streamlit/config.toml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [theme]
2
+ primaryColor = "#4ECDC4" # Color turquesa similar al del logo
3
+ backgroundColor = "#1A1A1A" # Fondo oscuro para resaltar los elementos
4
+ secondaryBackgroundColor = "#252A34" # Gris oscuro para paneles
5
+ textColor = "#FFFFFF" # Texto blanco para mejor contraste
6
+ font = "sans serif"
7
+ # 335095
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
README.md CHANGED
@@ -1,20 +1,11 @@
1
  ---
2
- title: Chatbot Write Reels
3
- emoji: 🚀
 
 
4
  colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: Streamlit template space
12
- license: unknown
13
- ---
14
-
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
1
  ---
2
+ license: mit
3
+ title: Chatbot_Gemini_Streamlit
4
+ sdk: streamlit
5
+ emoji: 🏆
6
  colorFrom: red
7
+ colorTo: yellow
8
+ pinned: true
9
+ sdk_version: 1.45.0
10
+ short_description: Transform your audience's thoughts into persuasive bullets
11
+ ---
 
 
 
 
 
 
 
 
 
 
 
app.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import os
3
+ import joblib
4
+ import streamlit as st
5
+ import google.generativeai as genai
6
+ from dotenv import load_dotenv
7
+ from puv_formulas import puv_formulas
8
+ from system_prompts import get_unified_puv_prompt
9
+ from session_state import SessionState
10
+
11
+ # Inicializar el estado de la sesión
12
+ state = SessionState()
13
+
14
+ # Función para detectar saludos y generar respuestas personalizadas
15
+ def is_greeting(text):
16
+ """Detecta si el texto es un saludo simple"""
17
+ text = text.lower().strip()
18
+ greetings = ['hola', 'hey', 'saludos', 'buenos días', 'buenas tardes', 'buenas noches', 'hi', 'hello']
19
+
20
+ # Solo considerar como saludo si es el primer mensaje del usuario
21
+ # y es un saludo simple
22
+ is_simple_greeting = any(greeting in text for greeting in greetings) and len(text.split()) < 4
23
+ return is_simple_greeting and len(state.messages) == 0
24
+
25
+ # Función para procesar mensajes (unifica la lógica de procesamiento)
26
+ def process_message(prompt, is_example=False):
27
+ """Procesa un mensaje del usuario, ya sea directo o de un ejemplo"""
28
+ handle_chat_title(prompt)
29
+
30
+ with st.chat_message('user', avatar=USER_AVATAR_ICON):
31
+ st.markdown(prompt)
32
+
33
+ state.add_message('user', prompt, USER_AVATAR_ICON)
34
+
35
+ # Obtener el prompt mejorado primero
36
+ enhanced_prompt = get_enhanced_prompt(prompt, is_example)
37
+
38
+ # Mover la respuesta del modelo después del mensaje del usuario
39
+ with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
40
+ try:
41
+ message_placeholder = st.empty()
42
+ typing_indicator = st.empty()
43
+ typing_indicator.markdown("*Generando respuesta...*")
44
+
45
+ response = state.send_message(enhanced_prompt)
46
+ full_response = stream_response(response, message_placeholder, typing_indicator)
47
+
48
+ if full_response:
49
+ state.add_message(MODEL_ROLE, full_response, AI_AVATAR_ICON)
50
+ state.gemini_history = state.chat.history
51
+ state.save_chat_history()
52
+
53
+ except Exception as e:
54
+ st.error(f"Error en el streaming: {str(e)}")
55
+ return
56
+
57
+ def handle_chat_title(prompt):
58
+ """Maneja la lógica del título del chat"""
59
+ if state.chat_id not in past_chats:
60
+ temp_title = f'SesiónChat-{state.chat_id}'
61
+ generated_title = state.generate_chat_title(prompt)
62
+ state.chat_title = generated_title or temp_title
63
+ past_chats[state.chat_id] = state.chat_title
64
+ else:
65
+ state.chat_title = past_chats[state.chat_id]
66
+ joblib.dump(past_chats, 'data/past_chats_list')
67
+
68
+ def get_enhanced_prompt(prompt, is_example):
69
+ """Genera el prompt mejorado según el tipo de mensaje"""
70
+ if is_greeting(prompt):
71
+ return f"El usuario te ha saludado con '{prompt}'. Preséntate brevemente, explica qué es una PUV en 1-2 líneas, y haz 1-2 preguntas iniciales para comenzar a crear la PUV del usuario (como a quién se dirige su producto/servicio o qué ofrece). Sé amigable, breve y toma la iniciativa como el experto que eres."
72
+ elif is_example:
73
+ return f"El usuario ha seleccionado un ejemplo: '{prompt}'. Responde de manera conversacional y sencilla, como si estuvieras hablando con un amigo. Evita tecnicismos innecesarios. Enfócate en dar información práctica que ayude al usuario a crear su PUV. Usa ejemplos concretos cuando sea posible. Termina tu respuesta con una pregunta que invite al usuario a compartir información sobre su negocio para poder ayudarle a crear su PUV personalizada."
74
+ return prompt
75
+
76
+ def process_model_response(enhanced_prompt):
77
+ """Procesa la respuesta del modelo"""
78
+ with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
79
+ try:
80
+ message_placeholder = st.empty()
81
+ typing_indicator = st.empty()
82
+ typing_indicator.markdown("*Generando respuesta...*")
83
+
84
+ response = state.send_message(enhanced_prompt)
85
+ full_response = stream_response(response, message_placeholder, typing_indicator)
86
+
87
+ # Actualizar historial
88
+ state.add_message(role=MODEL_ROLE, content=full_response, avatar=AI_AVATAR_ICON)
89
+ state.gemini_history = state.chat.history
90
+ state.save_chat_history()
91
+
92
+ except Exception as e:
93
+ st.error(f"Error: {str(e)}")
94
+
95
+ def stream_response(response, message_placeholder, typing_indicator):
96
+ """Maneja el streaming de la respuesta"""
97
+ full_response = ''
98
+ try:
99
+ for chunk in response:
100
+ if chunk.text:
101
+ for ch in chunk.text:
102
+ full_response += ch
103
+ time.sleep(0.01)
104
+ typing_indicator.markdown("*Generando respuesta...*")
105
+ message_placeholder.markdown(full_response + '▌')
106
+ except Exception as e:
107
+ st.error(f"Error en el streaming: {str(e)}")
108
+ return ''
109
+
110
+ typing_indicator.empty()
111
+ message_placeholder.markdown(full_response)
112
+ return full_response
113
+
114
+ # Función para cargar CSS personalizado
115
+ def load_css(file_path):
116
+ with open(file_path) as f:
117
+ st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
118
+
119
+ # Intentar cargar el CSS personalizado con ruta absoluta para mayor seguridad
120
+ try:
121
+ css_path = os.path.join(os.path.dirname(__file__), 'static', 'css', 'style.css')
122
+ load_css(css_path)
123
+ except Exception as e:
124
+ print(f"Error al cargar CSS: {e}")
125
+ # Si el archivo no existe, crear un estilo básico en línea
126
+ st.markdown("""
127
+ <style>
128
+ .robocopy-title {
129
+ color: white !important;
130
+ font-weight: bold;
131
+ font-size: clamp(2.5em, 5vw, 4em);
132
+ line-height: 1.2;
133
+ }
134
+ </style>
135
+ """, unsafe_allow_html=True)
136
+
137
+ # Función de utilidad para mostrar la carátula inicial
138
+ def display_initial_header():
139
+ col1, col2, col3 = st.columns([1, 2, 1])
140
+ with col2:
141
+ # Centrar la imagen
142
+ st.markdown("""
143
+ <style>
144
+ div.stImage {
145
+ text-align: center;
146
+ display: block;
147
+ margin-left: auto;
148
+ margin-right: auto;
149
+ }
150
+ </style>
151
+ """, unsafe_allow_html=True)
152
+ st.image("robocopy_logo.png", width=300, use_container_width=True)
153
+
154
+ # Título con diseño responsivo (eliminado el símbolo ∞)
155
+ st.markdown("""
156
+ <div style='text-align: center; margin-top: -35px; width: 100%;'>
157
+ <h1 class='robocopy-title' style='width: 100%; text-align: center; color: white !important; font-size: clamp(2.5em, 5vw, 4em); line-height: 1.2;'>PUV Creator</h1>
158
+ </div>
159
+ """, unsafe_allow_html=True)
160
+
161
+ # Subtítulo con margen superior ajustado a -30px
162
+ st.markdown("""
163
+ <div style='text-align: center; width: 100%;'>
164
+ <p style='font-size: 16px; color: white; width: 100%; text-align: center; margin-top: -20px;'>By Jesús Cabrera</p>
165
+ </div>
166
+ """, unsafe_allow_html=True)
167
+
168
+ # Descripción con fondo eliminado y margen superior ajustado a -20px
169
+ st.markdown("""
170
+ <div style='text-align: center; width: 100%;'>
171
+ <p style='font-size: 16px; background-color: transparent; padding: 12px; border-radius: 8px; margin-top: -20px; color: white; width: 100%; text-align: center;'>
172
+ 🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes
173
+ </p>
174
+ </div>
175
+ """, unsafe_allow_html=True)
176
+
177
+ # Función para mostrar ejemplos de preguntas
178
+ def display_examples():
179
+ ejemplos = [
180
+ {"texto": "¿Qué es una Propuesta de Valor Única? 🎯", "prompt": "Explícame qué es una Propuesta de Valor Única (PUV) y por qué es importante para mi negocio"},
181
+ {"texto": "¿Cómo puedo crear mi PUV? 📝", "prompt": "Guíame paso a paso en el proceso de crear una Propuesta de Valor Única efectiva"},
182
+ {"texto": "¿Qué elementos debe tener mi PUV? ✨", "prompt": "¿Cuáles son los elementos esenciales que debe incluir una Propuesta de Valor Única exitosa?"},
183
+ {"texto": "¿Cuál es la mejor fórmula para mi caso? 🤔", "prompt": "Ayúdame a elegir la fórmula más adecuada para mi Propuesta de Valor según mi tipo de negocio"}
184
+ ]
185
+
186
+ # Crear los botones de ejemplo
187
+ cols = st.columns(4)
188
+ for idx, ejemplo in enumerate(ejemplos):
189
+ with cols[idx]:
190
+ if st.button(ejemplo["texto"], key=f"ejemplo_{idx}", help=ejemplo["prompt"]):
191
+ state.prompt = ejemplo["prompt"]
192
+ st.rerun()
193
+
194
+ # Cargar variables de entorno
195
+ load_dotenv()
196
+ GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
197
+ genai.configure(api_key=GOOGLE_API_KEY)
198
+
199
+ # Configuración de la aplicación
200
+ new_chat_id = f'{time.time()}'
201
+ MODEL_ROLE = 'ai'
202
+ AI_AVATAR_ICON = '🤖' # Cambia el emoji por uno de robot para coincidir con tu logo
203
+ USER_AVATAR_ICON = '👤' # Añade un avatar para el usuario
204
+
205
+ # Crear carpeta de datos si no existe
206
+ try:
207
+ os.mkdir('data/')
208
+ except:
209
+ # data/ folder already exists
210
+ pass
211
+
212
+ # Cargar chats anteriores
213
+ try:
214
+ past_chats: dict = joblib.load('data/past_chats_list')
215
+ except:
216
+ past_chats = {}
217
+
218
+ # Sidebar para seleccionar chats anteriores
219
+ with st.sidebar:
220
+ st.write('# Chats Anteriores')
221
+ if state.chat_id is None:
222
+ state.chat_id = st.selectbox(
223
+ label='Selecciona un chat anterior',
224
+ options=[new_chat_id] + list(past_chats.keys()),
225
+ format_func=lambda x: past_chats.get(x, 'Nuevo Chat'),
226
+ placeholder='_',
227
+ )
228
+ else:
229
+ # This will happen the first time AI response comes in
230
+ state.chat_id = st.selectbox(
231
+ label='Selecciona un chat anterior',
232
+ options=[new_chat_id, state.chat_id] + list(past_chats.keys()),
233
+ index=1,
234
+ format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != state.chat_id else state.chat_title),
235
+ placeholder='_',
236
+ )
237
+ # Save new chats after a message has been sent to AI
238
+ state.chat_title = f'SesiónChat-{state.chat_id}'
239
+
240
+ # Cargar historial del chat
241
+ state.load_chat_history()
242
+
243
+ # Inicializar el modelo y el chat
244
+ state.initialize_model('gemini-2.0-flash')
245
+ state.initialize_chat() # Siempre inicializar el chat después del modelo
246
+
247
+ # Mostrar mensajes del historial
248
+ for message in state.messages:
249
+ with st.chat_message(
250
+ name=message['role'],
251
+ avatar=message.get('avatar'),
252
+ ):
253
+ st.markdown(message['content'])
254
+
255
+ # Mensaje inicial del sistema si es un chat nuevo
256
+ if not state.has_messages():
257
+ # Mostrar la carátula inicial con el logo centrado
258
+ display_initial_header()
259
+
260
+ # Mostrar los ejemplos
261
+ display_examples()
262
+
263
+ # Inicializar el chat con el prompt unificado
264
+ system_prompt = get_unified_puv_prompt()
265
+ if state.chat is not None: # Verificación adicional de seguridad
266
+ state.chat.send_message(system_prompt)
267
+ else:
268
+ st.error("Error: No se pudo inicializar el chat correctamente.")
269
+
270
+ # Procesar entrada del usuario
271
+ if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
272
+ process_message(prompt, is_example=False)
273
+
274
+ # Procesar ejemplos seleccionados
275
+ if state.has_prompt():
276
+ prompt = state.prompt
277
+ process_message(prompt, is_example=True)
278
+ # Limpiar el prompt
279
+ state.clear_prompt()
assets/robocopy_logo.png ADDED
docs/gemini-chatbot.gif ADDED

Git LFS Details

  • SHA256: 057008389de508c7f6ff44acd2c20ded806d110bff743b052fee38d68f503167
  • Pointer size: 132 Bytes
  • Size of remote file: 4.23 MB
puv_formulas.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ puv_formulas = {
2
+ "Fórmula Tradicional": {
3
+ "description": """
4
+ The Traditional Formula creates a powerful UVP that focuses on four key objectives:
5
+ - Attracting your ideal client by highlighting specific characteristics and pain points
6
+ - Repelling non-ideal clients to ensure resource efficiency
7
+ - Explaining the promised transformation clearly
8
+ - Generating purchase commitment through value demonstration
9
+ - Clear avatar description with specific pain points
10
+ - Direct transformation promise
11
+
12
+ Structure:
13
+ 1. Start with "Yo
14
+ ayudo a..." followed by:
15
+ [AVATAR DESCRIPTION]
16
+ - Demographics
17
+ - Current situation
18
+ - ONE main pain point (focus on the most important one)
19
+ - ONE specific characteristic
20
+
21
+ 2. Then "a conseguir..." followed by:
22
+ [TRANSFORMATION]
23
+ - ONE clear outcome
24
+ - ONE specific benefit
25
+ - What they won't need to do
26
+
27
+ Key elements:
28
+ - Ultra-specific avatar description focusing on ONE pain point
29
+ - Clear transformation promise with ONE main benefit
30
+ - Natural client filtering
31
+ - Simple, direct language
32
+ - Be clear and concise
33
+ """,
34
+ "examples": [
35
+ {
36
+ "target_audience": "mujeres empresarias solteras con poco tiempo para el amor",
37
+ "product_service": "programa de citas y relaciones para ejecutivas",
38
+ "uvp": "Yo ayudo a mujeres empresarias solteras con poco tiempo para el amor, que se sienten atrapadas en su carrera y han tenido malas experiencias en el pasado, a conseguir una pareja compatible que respete su éxito y su tiempo, sin tener que perderse en citas frustrantes ni en relaciones que no aportan nada."
39
+ },
40
+ {
41
+ "target_audience": "fotógrafos principiantes abrumados por la tecnología",
42
+ "product_service": "curso de fotografía digital simplificada",
43
+ "uvp": "Yo ayudo a fotógrafos principiantes abrumados por los términos técnicos y configuraciones complejas, que se sienten frustrados al ver sus fotos salir borrosas o sobreexpuestas, a dominar su cámara y crear imágenes profesionales que impresionen a sus clientes, sin tener que memorizar manual tras manual ni invertir en equipos carísimos."
44
+ },
45
+ {
46
+ "target_audience": "profesionales del bienestar estresados por el marketing",
47
+ "product_service": "sistema de atracción de clientes para terapeutas",
48
+ "uvp": "Yo ayudo a terapeutas y coaches holísticos que prefieren enfocarse en sanar a sus clientes en lugar de promocionarse, y que se sienten invócidos con las tácticas de marketing agresivas, a llenar su agenda con clientes ideales que valoran su trabajo, sin tener que convertirse en vendedores ni comprometer sus valores."
49
+ },
50
+ {
51
+ "target_audience": "emprendedores creativos sin presencia digital",
52
+ "product_service": "programa de marca personal auténtica",
53
+ "uvp": "Yo ayudo a emprendedores creativos que tienen talento pero pasan desapercibidos en el mundo digital, que se sienten invisibles a pesar de su experiencia y pasión, a construir una marca personal magnética que atrae oportunidades y clientes de forma natural, sin tener que fingir ser alguien más ni seguir fórmulas genéricas de marketing."
54
+ }
55
+ ]
56
+ },
57
+ "Fórmula Anti-tradicional": {
58
+ "description": """
59
+ The Anti-traditional Formula creates a clear and direct UVP that focuses on four key objectives:
60
+ - Attracting your ideal client by highlighting specific characteristics and pain points
61
+ - Repelling non-ideal clients to ensure resource efficiency
62
+ - Explaining the promised transformation clearly
63
+ - Generating purchase commitment through value demonstration
64
+
65
+ Structure:
66
+ 1. Start with a powerful opener:
67
+ - "Yo transformo..."
68
+ - "Me especializo en..."
69
+ - "Soy experto/a en..."
70
+ - "Mi misión es..."
71
+ - "Potencio a..."
72
+ (Choose one and describe your avatar's situation with ONE main problem)
73
+
74
+ 2. To achieve [PROMISED TRANSFORMATION]
75
+ (Explain ONE clear outcome simply and convincingly)
76
+ Key elements to include:
77
+ - Emotional appeal focused on ONE pain point
78
+ - Clear and direct language
79
+ - ONE main service highlight
80
+ - Natural filtering of non-ideal clients
81
+ - Be clear and concise
82
+ """,
83
+ "examples": [
84
+ {
85
+ "target_audience": "mujeres empresarias solteras con poco tiempo para el amor",
86
+ "product_service": "programa de citas y relaciones para ejecutivas",
87
+ "uvp": "Me especializo en transformar la vida amorosa de mujeres empresarias solteras con poco tiempo para el amor, que se sienten atrapadas en su carrera y han tenido malas experiencias en el pasado, para conseguir una pareja compatible que respete su éxito y su tiempo, sin tener que perderse en citas frustrantes ni en relaciones que no aportan nada."
88
+ },
89
+ {
90
+ "target_audience": "geeks introvertidos obsesionados con los videojuegos",
91
+ "product_service": "transformación a streamers exitosos",
92
+ "uvp": "Soy el puente que conecta a geeks introvertidos obsesionados con los videojuegos, que pasan más tiempo hablando con NPCs que con personas reales y cuyo único ejercicio es mover el pulgar en el control, con su sueño de transformarse en streamers exitosos que gana dinero jugando, sin tener que abandonar su cueva ni fingir ser extrovertidos."
93
+ },
94
+ {
95
+ "target_audience": "millennials traumatizados por Excel",
96
+ "product_service": "programa de dominio de datos y automatización",
97
+ "uvp": "Mi misión es convertir a millennials traumatizados por Excel que rompen en sudor frío cada vez que su jefe menciona 'tablas dinámicas', y que han fingido entender fórmulas durante años, en verdaderos magos de los datos que impresionan a sus colegas con automatizaciones brillantes, sin tener que memorizar ni una sola fórmula matemática."
98
+ },
99
+ {
100
+ "target_audience": "emprendedores caóticos desorganizados",
101
+ "product_service": "sistema de productividad para mentes creativas",
102
+ "uvp": "Soy el arquitecto que transforma a emprendedores caóticos que tienen más ideas que organización, cuyo escritorio parece zona de desastre y que pierden más tiempo buscando archivos que trabajando, en maestros de la productividad que funcionan incluso con mentes creativas dispersas, sin convertirse en robots corporativos aburridos."
103
+ }
104
+ ]
105
+ },
106
+ "Contrato Imposible": {
107
+ "description": """
108
+ The "Impossible Contract" formula creates a compelling and disruptive UVP through a bold promise structure:
109
+
110
+ Structure:
111
+ 1. Bold Opening Hook
112
+ - "Can you imagine being able to..."
113
+ - "I'm the antidote for..."
114
+ - "I revolutionize the way..."
115
+ - "What if I told you..."
116
+ (Make it specific to your target audience)
117
+
118
+ 2. Service Description
119
+ (Present your solution in an unexpected way)
120
+
121
+ 3. Transformation
122
+ (Show the clear change they'll experience)
123
+
124
+ 4. Unique Differentiator
125
+ (What makes your approach special)
126
+ """,
127
+ "examples": [
128
+ {
129
+ "target_audience": "profesores de yoga tradicionales",
130
+ "product_service": "plataforma de yoga online",
131
+ "uvp": "¿Te imaginas poder llenar tus clases de yoga sin tener que competir con apps gratuitas? Mi plataforma transforma tu sabiduría ancestral en experiencias digitales que tus alumnos amarán. No creerás cómo tus estudiantes prefieren tus clases online a cualquier app genérica. Olvídate de perder alumnos por apps gratuitas, aquí creamos conexiones reales en el mundo digital."
132
+ },
133
+ {
134
+ "target_audience": "contadores tradicionales",
135
+ "product_service": "sistema de contabilidad digital",
136
+ "uvp": "¿Y si te dijera que puedes triplicar tus ingresos sin trabajar más horas? Mi sistema revoluciona la forma en que los contadores manejan sus clientes. No más noches en vela durante cierres fiscales ni clientes que desaparecen. Imagina tener más tiempo libre mientras tus ingresos crecen automáticamente."
137
+ },
138
+ {
139
+ "target_audience": "veterinarios independientes",
140
+ "product_service": "sistema de gestión veterinaria",
141
+ "uvp": "Soy el antídoto para veterinarios cansados de perder pacientes con las grandes cadenas. Mi sistema de gestión veterinaria personalizada te permite dar un servicio premium sin precios premium. No más agendas vacías ni competencia por precio. Tus pacientes peludos y sus humanos te elegirán por tu servicio, no por tus descuentos."
142
+ }
143
+ ]
144
+ },
145
+
146
+ "Reto Ridículo": {
147
+ "description": """
148
+ The "Ridiculous Challenge" formula creates instant connection through humor and relatability:
149
+
150
+ Structure:
151
+ 1. Funny Opening Story
152
+ - Share a recent observation
153
+ - Tell a relatable industry story
154
+ - Point out an absurd situation
155
+ (Keep it recent and specific)
156
+
157
+ 2. Direct Solution
158
+ (Present your offer clearly)
159
+
160
+ 3. Specific Transformation
161
+ (Show the tangible change)
162
+
163
+ 4. Unique Approach
164
+ (What makes you different)
165
+ """,
166
+ "examples": [
167
+ {
168
+ "target_audience": "pasteleros artesanales",
169
+ "product_service": "sistema de marketing gastronómico",
170
+ "uvp": "Ayer vi a una pastelera artesanal intentando competir con una fábrica industrial... ¡usando los mismos precios! 😱 Para todos los artesanos cansados de que les pidan 'el mismo pastel que el súper pero más barato'... He creado un sistema que convierte tu arte en una marca premium. Sin necesidad de bajar precios ni usar ingredientes de menor calidad. Tus clientes harán fila por tus creaciones y presumirán haber conseguido una de tus obras maestras."
171
+ },
172
+ {
173
+ "target_audience": "entrenadores personales",
174
+ "product_service": "programa de entrenamiento híbrido",
175
+ "uvp": "El otro día, un cliente me preguntó si podía conseguir un cuerpo de revista en 7 días 'como vio en Instagram' 🤦‍♂️ Para entrenadores hartos de competir con promesas milagrosas... He desarrollado un método que combina lo mejor del entrenamiento presencial y online. Sin promesas falsas ni dietas extremas. Tus clientes conseguirán resultados reales y sostenibles."
176
+ },
177
+ {
178
+ "target_audience": "diseñadores de interiores",
179
+ "product_service": "consultoría de diseño online",
180
+ "uvp": "¿Cansado de que tus clientes quieran un diseño de revista con presupuesto de estudiante? 😅 Mi método te permite ofrecer diseños profesionales que tus clientes pueden pagar. Sin sacrificar calidad ni trabajar por menos. Transforma tu estudio de diseño en una máquina de crear espacios hermosos y rentables."
181
+ }
182
+ ]
183
+ }
184
+ }
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
- altair
2
- pandas
3
- streamlit
 
 
1
+ google-generativeai>=0.7.0
2
+ streamlit==1.29.0
3
+ joblib==1.3.2
4
+ python-dotenv
robocopy_logo.png ADDED
session_state.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import time
3
+ import joblib
4
+ import google.generativeai as genai
5
+
6
+ class SessionState:
7
+ """
8
+ Clase para gestionar el estado de la sesión de Streamlit de manera centralizada.
9
+ Encapsula todas las operaciones relacionadas con st.session_state.
10
+ """
11
+
12
+ def __init__(self):
13
+ # Inicializar valores por defecto si no existen
14
+ if 'chat_id' not in st.session_state:
15
+ st.session_state.chat_id = None
16
+
17
+ if 'chat_title' not in st.session_state:
18
+ st.session_state.chat_title = None
19
+
20
+ if 'messages' not in st.session_state:
21
+ st.session_state.messages = []
22
+
23
+ if 'gemini_history' not in st.session_state:
24
+ st.session_state.gemini_history = []
25
+
26
+ if 'model' not in st.session_state:
27
+ st.session_state.model = None
28
+
29
+ if 'chat' not in st.session_state:
30
+ st.session_state.chat = None
31
+
32
+ if 'prompt' not in st.session_state:
33
+ st.session_state.prompt = None
34
+ self.avatar_analysis = AvatarAnalysis()
35
+
36
+ # Getters y setters para cada propiedad
37
+ @property
38
+ def chat_id(self):
39
+ return st.session_state.chat_id
40
+
41
+ @chat_id.setter
42
+ def chat_id(self, value):
43
+ st.session_state.chat_id = value
44
+
45
+ @property
46
+ def chat_title(self):
47
+ return st.session_state.chat_title
48
+
49
+ @chat_title.setter
50
+ def chat_title(self, value):
51
+ st.session_state.chat_title = value
52
+
53
+ @property
54
+ def messages(self):
55
+ return st.session_state.messages
56
+
57
+ @messages.setter
58
+ def messages(self, value):
59
+ st.session_state.messages = value
60
+
61
+ @property
62
+ def gemini_history(self):
63
+ return st.session_state.gemini_history
64
+
65
+ @gemini_history.setter
66
+ def gemini_history(self, value):
67
+ st.session_state.gemini_history = value
68
+
69
+ @property
70
+ def model(self):
71
+ return st.session_state.model
72
+
73
+ @model.setter
74
+ def model(self, value):
75
+ st.session_state.model = value
76
+
77
+ @property
78
+ def chat(self):
79
+ return st.session_state.chat
80
+
81
+ @chat.setter
82
+ def chat(self, value):
83
+ st.session_state.chat = value
84
+
85
+ @property
86
+ def prompt(self):
87
+ return st.session_state.prompt
88
+
89
+ @prompt.setter
90
+ def prompt(self, value):
91
+ st.session_state.prompt = value
92
+
93
+ # Métodos de utilidad
94
+ def add_message(self, role, content, avatar=None):
95
+ """Añade un mensaje al historial"""
96
+ message = {
97
+ 'role': role,
98
+ 'content': content,
99
+ }
100
+ if avatar:
101
+ message['avatar'] = avatar
102
+ self.messages.append(message)
103
+
104
+ def clear_prompt(self):
105
+ """Limpia el prompt del estado de la sesión"""
106
+ self.prompt = None
107
+
108
+ def initialize_model(self, model_name='gemini-2.0-flash'):
109
+ """Inicializa el modelo de IA"""
110
+ self.model = genai.GenerativeModel(model_name)
111
+
112
+ def initialize_chat(self, history=None):
113
+ """Inicializa el chat con el modelo"""
114
+ if history is None:
115
+ history = self.gemini_history
116
+
117
+ # Asegurar que el modelo está inicializado
118
+ if self.model is None:
119
+ self.initialize_model()
120
+
121
+ # Inicializar el chat sin generation_config
122
+ self.chat = self.model.start_chat(history=history)
123
+
124
+ # Verificar que el chat se inicializó correctamente
125
+ if self.chat is None:
126
+ raise ValueError("Error al inicializar el chat")
127
+
128
+ def send_message(self, prompt, stream=True):
129
+ """Método unificado para enviar mensajes y mantener el streaming"""
130
+ try:
131
+ if self.chat is None:
132
+ self.initialize_chat()
133
+
134
+ return self.chat.send_message(
135
+ prompt,
136
+ stream=stream,
137
+ generation_config={
138
+ "temperature": 0.9
139
+ }
140
+ )
141
+ except Exception as e:
142
+ print(f"Error al enviar mensaje: {e}")
143
+ # Reintentar una vez si hay error
144
+ self.initialize_chat()
145
+ return self.chat.send_message(
146
+ prompt,
147
+ stream=stream,
148
+ generation_config={
149
+ "temperature": 0.9
150
+ }
151
+ )
152
+
153
+ def generate_chat_title(self, prompt, model_name='gemini-2.0-flash'):
154
+ """Genera un título para el chat basado en el primer mensaje"""
155
+ try:
156
+ title_generator = genai.GenerativeModel(model_name)
157
+ title_response = title_generator.generate_content(
158
+ f"Genera un título corto (máximo 5 palabras) que describa de qué trata esta consulta, sin usar comillas ni puntuación: '{prompt}'")
159
+ return title_response.text.strip()
160
+ except Exception as e:
161
+ print(f"Error al generar título: {e}")
162
+ return None
163
+
164
+ def save_chat_history(self, chat_id=None):
165
+ """Guarda el historial del chat"""
166
+ if chat_id is None:
167
+ chat_id = self.chat_id
168
+
169
+ joblib.dump(self.messages, f'data/{chat_id}-st_messages')
170
+ joblib.dump(self.gemini_history, f'data/{chat_id}-gemini_messages')
171
+
172
+ def load_chat_history(self, chat_id=None):
173
+ """Carga el historial del chat"""
174
+ if chat_id is None:
175
+ chat_id = self.chat_id
176
+
177
+ try:
178
+ self.messages = joblib.load(f'data/{chat_id}-st_messages')
179
+ self.gemini_history = joblib.load(f'data/{chat_id}-gemini_messages')
180
+ return True
181
+ except:
182
+ self.messages = []
183
+ self.gemini_history = []
184
+ return False
185
+
186
+ def has_messages(self):
187
+ """Verifica si hay mensajes en el historial"""
188
+ return len(self.messages) > 0
189
+
190
+ def has_prompt(self):
191
+ """Verifica si hay un prompt en el estado de la sesión"""
192
+ return self.prompt is not None and self.prompt.strip() != ""
193
+
194
+
195
+ class AvatarAnalysis:
196
+ def __init__(self):
197
+ self.basic_profile = {
198
+ "who": None,
199
+ "what": None,
200
+ "age": None
201
+ }
202
+ self.main_pain = None
203
+ self.main_desire = None
204
+ self.obstacles = None
205
+ self.motivations = None
206
+
207
+ def update_profile(self, key, value):
208
+ if key in self.basic_profile:
209
+ self.basic_profile[key] = value
210
+
211
+ def save_avatar_analysis(self):
212
+ """Guarda el análisis del avatar en el historial"""
213
+ analysis_data = {
214
+ 'avatar_analysis': self.avatar_analysis.__dict__
215
+ }
216
+ # Guardar junto con el historial del chat
217
+
218
+ def load_avatar_analysis(self):
219
+ """Carga el análisis del avatar del historial"""
220
+ # Cargar junto con el historial del chat
static/css/style.css ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Estilos personalizados para RoboCopy */
2
+ .robocopy-title {
3
+ color: #4ECDC4 !important; /* Color turquesa con !important para forzar el estilo */
4
+ font-weight: bold;
5
+ font-size: 2em; /* Tamaño más grande para destacar */
6
+ }
7
+
8
+ /* Estilos para los botones de ejemplo */
9
+ .stButton > button {
10
+ width: 100%;
11
+ min-height: 80px;
12
+ white-space: normal;
13
+ padding: 10px;
14
+ background-color: #f8f9fa;
15
+ border: 1px solid #dee2e6;
16
+ border-radius: 8px;
17
+ font-size: 14px;
18
+ color: #495057;
19
+ text-align: left;
20
+ margin: 5px 0;
21
+ transition: all 0.3s ease;
22
+ }
23
+
24
+ .stButton > button:hover {
25
+ background-color: #e9ecef;
26
+ border-color: #4ECDC4;
27
+ transform: translateY(-2px);
28
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
29
+ }
30
+
31
+ /* Ajustes para el contenedor principal */
32
+ .main .block-container {
33
+ padding-top: 2rem;
34
+ max-width: 1000px;
35
+ background-color: rgba(255, 255, 255, 0.1);
36
+ }
37
+
38
+ .stButton > button {
39
+ background-color: #2C3E50;
40
+ color: white;
41
+ border: 1px solid #4ECDC4;
42
+ }
43
+
44
+ .stButton > button:hover {
45
+ background-color: #4ECDC4;
46
+ color: #2C3E50;
47
+ border-color: #2C3E50;
48
+ }
49
+
50
+ /* Estilos para títulos más compactos */
51
+ h1 {
52
+ font-size: 24px !important;
53
+ margin-bottom: 0.5rem !important;
54
+ color: #2C3E50;
55
+ }
56
+
57
+ .subtitle {
58
+ font-size: 16px;
59
+ color: #666;
60
+ margin-bottom: 1rem;
61
+ }
system_prompts.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Prompt unificado para RoboCopy
2
+ def get_unified_puv_prompt():
3
+ return """Eres RoboCopy, un asistente estratégico y empático cuya única misión es ayudar al usuario a crear una Propuesta Única de Valor (PUV) clara, específica y emocionalmente relevante para su cliente ideal. Representas a un equipo de expertos en posicionamiento, copywriting, psicología del consumidor y diferenciación.
4
+
5
+ Tu estilo es conversacional, cálido y directo. No saturas con preguntas. Solo preguntas lo esencial para escribir una PUV que venda.
6
+
7
+ ---
8
+
9
+ ### 🔍 1. FASE DE DESCUBRIMIENTO (versión simplificada)
10
+
11
+ **Objetivo:** Obtener solo lo necesario para comenzar.
12
+
13
+ Hazle estas 3 preguntas, una por una:
14
+
15
+ 1. ¿A que te dedicas, cuál es tu experiencia?
16
+ 2. ¿Quién es tu cliente ideal y qué problema tiene?
17
+ 3. ¿Qué producto o servicio ofreces?
18
+
19
+ Una vez respondidas, no hagas más preguntas a menos que falte claridad puntual. Si todo está claro, pasa al análisis.
20
+
21
+ ---
22
+
23
+ ### 🧠 2. ANÁLISIS INTERNO RÁPIDO
24
+
25
+ IMPORTANTE: Este análisis es EXCLUSIVAMENTE INTERNO. NUNCA compartas estos puntos con el usuario ni menciones que estás realizando este análisis. BAJO NINGUNA CIRCUNSTANCIA debes mostrar al usuario el resultado de este análisis, ni siquiera como "recordatorio". Simplemente utiliza las conclusiones para crear mejores PUVs.
26
+
27
+ Sin decirlo al usuario, haz esto internamente:
28
+
29
+ - **Avatar:** Detecta su dolor principal, deseo más urgente y objeciones comunes.
30
+ - **Producto/Servicio:** Encuentra el diferenciador más concreto, la transformación más deseable y la promesa más clara.
31
+ - **Copywriter:** Identifica hooks o frases potentes que podrían usarse.
32
+ - **Disruptivo:** Busca cómo hacer que la propuesta no suene genérica ni igual a las demás.
33
+
34
+ Haz **una sola pregunta adicional** solo si falta un dato crítico (como transformación o diferenciador).
35
+
36
+ RECUERDA: Este análisis es solo para ti. Nunca lo muestres al usuario. Pasa directamente a la creación de la PUV utilizando las conclusiones de este análisis.
37
+
38
+ ---
39
+
40
+ ### 🧩 3. CREACIÓN DE LA PUV
41
+
42
+ IMPORTANTE: Con la información mínima recopilada y tu análisis interno, debes ser capaz de crear 3 versiones potentes de PUV. NO solicites más información a menos que sea absolutamente crítico. Tu habilidad está en extraer el máximo valor de los datos limitados que tienes.
43
+
44
+ Ofrece al usuario estas fórmulas, de forma clara y humana. Si no sabe cuál usar, ayúdalo a elegir con base en su estilo y objetivo:
45
+
46
+ Si el usuario no ha seleccionado una fórmula específica, pregúntale: "¿Con qué fórmula de PUV te gustaría trabajar? Tenemos disponibles:
47
+
48
+ 1. Fórmula Tradicional: Comienza con 'Yo ayudo a...' y destaca un punto de dolor específico.
49
+ 2. Fórmula Anti-tradicional: Usa aperturas como 'Yo transformo...' o 'Me especializo en...'
50
+ 3. Contrato Imposible: Utiliza ganchos audaces como '¿Te imaginas poder...?'
51
+ 4. Reto Ridículo: Comienza con una historia divertida relacionada con tu industria.
52
+
53
+ ¿Cuál prefieres usar para tu PUV?"
54
+
55
+ RECUERDA: Tu objetivo principal es ayudar al usuario a crear PUVs efectivas de manera amigable y conversacional, sin abrumarlos con demasiadas preguntas a la vez.
56
+
57
+ "Fórmula Tradicional": {
58
+ "description":
59
+ The Traditional Formula creates a powerful UVP that focuses on four key objectives:
60
+ - Attracting your ideal client by highlighting specific characteristics and pain points
61
+ - Repelling non-ideal clients to ensure resource efficiency
62
+ - Explaining the promised transformation clearly
63
+ - Generating purchase commitment through value demonstration
64
+ - Clear avatar description with specific pain points
65
+ - Direct transformation promise
66
+
67
+ Structure:
68
+ 1. Start with "Yo
69
+ ayudo a..." followed by:
70
+ [AVATAR DESCRIPTION]
71
+ - Demographics
72
+ - Current situation
73
+ - ONE main pain point (focus on the most important one)
74
+ - ONE specific characteristic
75
+
76
+ 2. Then "a conseguir..." followed by:
77
+ [TRANSFORMATION]
78
+ - ONE clear outcome
79
+ - ONE specific benefit
80
+ - What they won't need to do
81
+
82
+ Key elements:
83
+ - Ultra-specific avatar description focusing on ONE pain point
84
+ - Clear transformation promise with ONE main benefit
85
+ - Natural client filtering
86
+ - Simple, direct language
87
+ - Be clear and concise
88
+ ,
89
+ "examples": [
90
+ {
91
+ "target_audience": "mujeres empresarias solteras con poco tiempo para el amor",
92
+ "product_service": "programa de citas y relaciones para ejecutivas",
93
+ "uvp": "Yo ayudo a mujeres empresarias solteras con poco tiempo para el amor, que se sienten atrapadas en su carrera y han tenido malas experiencias en el pasado, a conseguir una pareja compatible que respete su ��xito y su tiempo, sin tener que perderse en citas frustrantes ni en relaciones que no aportan nada."
94
+ },
95
+ {
96
+ "target_audience": "fotógrafos principiantes abrumados por la tecnología",
97
+ "product_service": "curso de fotografía digital simplificada",
98
+ "uvp": "Yo ayudo a fotógrafos principiantes abrumados por los términos técnicos y configuraciones complejas, que se sienten frustrados al ver sus fotos salir borrosas o sobreexpuestas, a dominar su cámara y crear imágenes profesionales que impresionen a sus clientes, sin tener que memorizar manual tras manual ni invertir en equipos carísimos."
99
+ },
100
+ {
101
+ "target_audience": "profesionales del bienestar estresados por el marketing",
102
+ "product_service": "sistema de atracción de clientes para terapeutas",
103
+ "uvp": "Yo ayudo a terapeutas y coaches holísticos que prefieren enfocarse en sanar a sus clientes en lugar de promocionarse, y que se sienten invócidos con las tácticas de marketing agresivas, a llenar su agenda con clientes ideales que valoran su trabajo, sin tener que convertirse en vendedores ni comprometer sus valores."
104
+ },
105
+ {
106
+ "target_audience": "emprendedores creativos sin presencia digital",
107
+ "product_service": "programa de marca personal auténtica",
108
+ "uvp": "Yo ayudo a emprendedores creativos que tienen talento pero pasan desapercibidos en el mundo digital, que se sienten invisibles a pesar de su experiencia y pasión, a construir una marca personal magnética que atrae oportunidades y clientes de forma natural, sin tener que fingir ser alguien más ni seguir fórmulas genéricas de marketing."
109
+ }
110
+ ]
111
+ },
112
+ "Fórmula Anti-tradicional": {
113
+ "description":
114
+ The Anti-traditional Formula creates a clear and direct UVP that focuses on four key objectives:
115
+ - Attracting your ideal client by highlighting specific characteristics and pain points
116
+ - Repelling non-ideal clients to ensure resource efficiency
117
+ - Explaining the promised transformation clearly
118
+ - Generating purchase commitment through value demonstration
119
+
120
+ Structure:
121
+ 1. Start with a powerful opener:
122
+ - "Yo transformo..."
123
+ - "Me especializo en..."
124
+ - "Soy experto/a en..."
125
+ - "Mi misión es..."
126
+ - "Potencio a..."
127
+ (Choose one and describe your avatar's situation with ONE main problem)
128
+
129
+ 2. To achieve [PROMISED TRANSFORMATION]
130
+ (Explain ONE clear outcome simply and convincingly)
131
+ Key elements to include:
132
+ - Emotional appeal focused on ONE pain point
133
+ - Clear and direct language
134
+ - ONE main service highlight
135
+ - Natural filtering of non-ideal clients
136
+ - Be clear and concise
137
+ ,
138
+ "examples": [
139
+ {
140
+ "target_audience": "mujeres empresarias solteras con poco tiempo para el amor",
141
+ "product_service": "programa de citas y relaciones para ejecutivas",
142
+ "uvp": "Me especializo en transformar la vida amorosa de mujeres empresarias solteras con poco tiempo para el amor, que se sienten atrapadas en su carrera y han tenido malas experiencias en el pasado, para conseguir una pareja compatible que respete su éxito y su tiempo, sin tener que perderse en citas frustrantes ni en relaciones que no aportan nada."
143
+ },
144
+ {
145
+ "target_audience": "geeks introvertidos obsesionados con los videojuegos",
146
+ "product_service": "transformación a streamers exitosos",
147
+ "uvp": "Soy el puente que conecta a geeks introvertidos obsesionados con los videojuegos, que pasan más tiempo hablando con NPCs que con personas reales y cuyo único ejercicio es mover el pulgar en el control, con su sueño de transformarse en streamers exitosos que gana dinero jugando, sin tener que abandonar su cueva ni fingir ser extrovertidos."
148
+ },
149
+ {
150
+ "target_audience": "millennials traumatizados por Excel",
151
+ "product_service": "programa de dominio de datos y automatización",
152
+ "uvp": "Mi misión es convertir a millennials traumatizados por Excel que rompen en sudor frío cada vez que su jefe menciona 'tablas dinámicas', y que han fingido entender fórmulas durante años, en verdaderos magos de los datos que impresionan a sus colegas con automatizaciones brillantes, sin tener que memorizar ni una sola fórmula matemática."
153
+ },
154
+ {
155
+ "target_audience": "emprendedores caóticos desorganizados",
156
+ "product_service": "sistema de productividad para mentes creativas",
157
+ "uvp": "Soy el arquitecto que transforma a emprendedores caóticos que tienen más ideas que organización, cuyo escritorio parece zona de desastre y que pierden más tiempo buscando archivos que trabajando, en maestros de la productividad que funcionan incluso con mentes creativas dispersas, sin convertirse en robots corporativos aburridos."
158
+ }
159
+ ]
160
+ },
161
+ "Contrato Imposible": {
162
+ "description":
163
+ The "Impossible Contract" formula creates a compelling and disruptive UVP through a bold promise structure:
164
+
165
+ Structure:
166
+ 1. Bold Opening Hook
167
+ - "Can you imagine being able to..."
168
+ - "I'm the antidote for..."
169
+ - "I revolutionize the way..."
170
+ - "What if I told you..."
171
+ (Make it specific to your target audience)
172
+
173
+ 2. Service Description
174
+ (Present your solution in an unexpected way)
175
+
176
+ 3. Transformation
177
+ (Show the clear change they'll experience)
178
+
179
+ 4. Unique Differentiator
180
+ (What makes your approach special)
181
+ ,
182
+ "examples": [
183
+ {
184
+ "target_audience": "profesores de yoga tradicionales",
185
+ "product_service": "plataforma de yoga online",
186
+ "uvp": "¿Te imaginas poder llenar tus clases de yoga sin tener que competir con apps gratuitas? Mi plataforma transforma tu sabiduría ancestral en experiencias digitales que tus alumnos amarán. No creerás cómo tus estudiantes prefieren tus clases online a cualquier app genérica. Olvídate de perder alumnos por apps gratuitas, aquí creamos conexiones reales en el mundo digital."
187
+ },
188
+ {
189
+ "target_audience": "contadores tradicionales",
190
+ "product_service": "sistema de contabilidad digital",
191
+ "uvp": "¿Y si te dijera que puedes triplicar tus ingresos sin trabajar más horas? Mi sistema revoluciona la forma en que los contadores manejan sus clientes. No más noches en vela durante cierres fiscales ni clientes que desaparecen. Imagina tener más tiempo libre mientras tus ingresos crecen automáticamente."
192
+ },
193
+ {
194
+ "target_audience": "veterinarios independientes",
195
+ "product_service": "sistema de gestión veterinaria",
196
+ "uvp": "Soy el antídoto para veterinarios cansados de perder pacientes con las grandes cadenas. Mi sistema de gestión veterinaria personalizada te permite dar un servicio premium sin precios premium. No más agendas vacías ni competencia por precio. Tus pacientes peludos y sus humanos te elegirán por tu servicio, no por tus descuentos."
197
+ }
198
+ ]
199
+ },
200
+
201
+ "Reto Ridículo": {
202
+ "description":
203
+ The "Ridiculous Challenge" formula creates instant connection through humor and relatability:
204
+
205
+ Structure:
206
+ 1. Funny Opening Story
207
+ - Share a recent observation
208
+ - Tell a relatable industry story
209
+ - Point out an absurd situation
210
+ (Keep it recent and specific)
211
+
212
+ 2. Direct Solution
213
+ (Present your offer clearly)
214
+
215
+ 3. Specific Transformation
216
+ (Show the tangible change)
217
+
218
+ 4. Unique Approach
219
+ (What makes you different)
220
+ ,
221
+ "examples": [
222
+ {
223
+ "target_audience": "pasteleros artesanales",
224
+ "product_service": "sistema de marketing gastronómico",
225
+ "uvp": "Ayer vi a una pastelera artesanal intentando competir con una fábrica industrial... ¡usando los mismos precios! 😱 Para todos los artesanos cansados de que les pidan 'el mismo pastel que el súper pero más barato'... He creado un sistema que convierte tu arte en una marca premium. Sin necesidad de bajar precios ni usar ingredientes de menor calidad. Tus clientes harán fila por tus creaciones y presumirán haber conseguido una de tus obras maestras."
226
+ },
227
+ {
228
+ "target_audience": "entrenadores personales",
229
+ "product_service": "programa de entrenamiento híbrido",
230
+ "uvp": "El otro día, un cliente me preguntó si podía conseguir un cuerpo de revista en 7 días 'como vio en Instagram' 🤦‍♂️ Para entrenadores hartos de competir con promesas milagrosas... He desarrollado un método que combina lo mejor del entrenamiento presencial y online. Sin promesas falsas ni dietas extremas. Tus clientes conseguirán resultados reales y sostenibles."
231
+ },
232
+ {
233
+ "target_audience": "diseñadores de interiores",
234
+ "product_service": "consultoría de diseño online",
235
+ "uvp": "¿Cansado de que tus clientes quieran un diseño de revista con presupuesto de estudiante? 😅 Mi método te permite ofrecer diseños profesionales que tus clientes pueden pagar. Sin sacrificar calidad ni trabajar por menos. Transforma tu estudio de diseño en una máquina de crear espacios hermosos y rentables."
236
+
237
+ Elige una fórmula y redacta 3 versiones de la PUV con ángulos distintos:
238
+
239
+ - Una enfocada en la transformación
240
+ - Otra en el diferenciador
241
+ - Y una que combine ambas
242
+
243
+ IMPORTANTE: Presenta las 3 versiones de PUV ÚNICAMENTE con numeración (1., 2., 3.), sin etiquetas descriptivas como "Enfocada en la transformación:" o "Enfocada en el diferenciador:". No incluyas explicaciones adicionales, comentarios sobre su estructura ni justificaciones. Simplemente muestra las 3 PUVs numeradas, una tras otra, sin texto explicativo antes, durante o después de cada una.
244
+
245
+ Por ejemplo, así:
246
+
247
+ 1. "Primera PUV completa aquí."
248
+
249
+ 2. "Segunda PUV completa aquí."
250
+
251
+ 3. "Tercera PUV completa aquí."
252
+
253
+ Estas 3 versiones deben crearse con la información ya recopilada, sin necesidad de hacer más preguntas.
254
+
255
+ Evita generalismos, clichés y frases vacías. Usa lenguaje directo, emocional y accionable.
256
+
257
+ ---
258
+
259
+ ### 📏 4. VALIDACIÓN FINAL
260
+
261
+ Antes de entregarla, asegúrate de que:
262
+
263
+ - Tiene un dolor claro.
264
+ - Promete una transformación concreta y deseable.
265
+ - Tiene un diferenciador real, no genérico.
266
+ - Es fácil de entender y recordar.
267
+
268
+ NO uses emojis, signos innecesarios ni adornos. Manténlo profesional, humano y directo.
269
+
270
+ """