Spaces:
Running
Running
Refactor: almacenar conversaciones y audios en /tmp
Browse files- app.py +2 -1
- chatbot.log +0 -0
- error.log +0 -0
- models/chatbot_model.py +29 -28
app.py
CHANGED
@@ -10,6 +10,7 @@ logging.basicConfig(
|
|
10 |
level=logging.ERROR,
|
11 |
format='%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s',
|
12 |
handlers=[
|
|
|
13 |
logging.FileHandler("/tmp/error.log"),
|
14 |
logging.StreamHandler()
|
15 |
]
|
@@ -60,4 +61,4 @@ def get_bot_response():
|
|
60 |
if __name__ == '__main__':
|
61 |
# Ajustamos para leer la variable de entorno PORT (o usar 7860 por defecto)
|
62 |
port = int(os.environ.get("PORT", 7860))
|
63 |
-
app.run(host="0.0.0.0", port=port, debug=True)
|
|
|
10 |
level=logging.ERROR,
|
11 |
format='%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s',
|
12 |
handlers=[
|
13 |
+
# Cambiamos a /tmp/error.log para que sea escribible en Hugging Face Spaces
|
14 |
logging.FileHandler("/tmp/error.log"),
|
15 |
logging.StreamHandler()
|
16 |
]
|
|
|
61 |
if __name__ == '__main__':
|
62 |
# Ajustamos para leer la variable de entorno PORT (o usar 7860 por defecto)
|
63 |
port = int(os.environ.get("PORT", 7860))
|
64 |
+
app.run(host="0.0.0.0", port=port, debug=True)
|
chatbot.log
DELETED
File without changes
|
error.log
DELETED
File without changes
|
models/chatbot_model.py
CHANGED
@@ -21,17 +21,23 @@ class MentalHealthChatbot:
|
|
21 |
# Configuraci贸n del logging
|
22 |
self.logger = logging.getLogger(__name__)
|
23 |
self.logger.setLevel(logging.INFO)
|
24 |
-
|
|
|
|
|
25 |
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
26 |
handler.setFormatter(formatter)
|
27 |
if not self.logger.handlers:
|
28 |
self.logger.addHandler(handler)
|
29 |
|
|
|
|
|
|
|
|
|
30 |
try:
|
31 |
self.logger.info("Cargando el tokenizador y el modelo BERT fine-tuned...")
|
32 |
|
33 |
-
# Crear carpeta
|
34 |
-
os.makedirs(
|
35 |
|
36 |
self.tokenizer = BertTokenizer.from_pretrained(model_path)
|
37 |
self.model = BertForSequenceClassification.from_pretrained(model_path).to(self.device)
|
@@ -84,9 +90,10 @@ class MentalHealthChatbot:
|
|
84 |
|
85 |
def get_emotion_prediction(self, text: str) -> Tuple[str, float]:
|
86 |
"""Predice la emoci贸n del texto usando el modelo fine-tuned."""
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
90 |
|
91 |
try:
|
92 |
inputs = self.tokenizer.encode_plus(
|
@@ -115,32 +122,23 @@ class MentalHealthChatbot:
|
|
115 |
def generate_response(self, user_input: str) -> Dict[str, Any]:
|
116 |
"""Genera una respuesta basada en el input del usuario."""
|
117 |
try:
|
118 |
-
# Preprocesar texto
|
119 |
processed_text = self.preprocess_text(user_input)
|
120 |
self.logger.info(f"Texto procesado: {processed_text}")
|
121 |
|
122 |
-
# Verificar emergencia
|
123 |
if self.detect_emergency(processed_text):
|
124 |
emotion = 'EMERGENCIA'
|
125 |
confidence = 1.0
|
126 |
self.logger.info("Emergencia detectada en el mensaje del usuario.")
|
127 |
else:
|
128 |
-
# Predecir emoci贸n
|
129 |
emotion, confidence = self.get_emotion_prediction(processed_text)
|
130 |
|
131 |
-
# Seleccionar respuesta
|
132 |
responses = self.responses.get(emotion, self.responses.get('CONFUSI脫N', ["Lo siento, no he entendido tu mensaje."]))
|
133 |
-
|
134 |
response = np.random.choice(responses)
|
135 |
self.logger.info(f"Respuesta seleccionada: {response}")
|
136 |
|
137 |
-
# Generar audio
|
138 |
audio_path = self.generate_audio(response)
|
139 |
|
140 |
-
# Actualizar historial
|
141 |
self.update_conversation_history(user_input, response, emotion)
|
142 |
-
|
143 |
-
# Guardar historial despu茅s de actualizar
|
144 |
self.save_conversation_history()
|
145 |
|
146 |
return {
|
@@ -162,15 +160,19 @@ class MentalHealthChatbot:
|
|
162 |
}
|
163 |
|
164 |
def generate_audio(self, text: str) -> str:
|
165 |
-
"""
|
|
|
|
|
|
|
|
|
166 |
try:
|
167 |
filename = f"response_{datetime.now().strftime('%Y%m%d_%H%M%S_%f')}.mp3"
|
168 |
-
|
|
|
169 |
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
170 |
|
171 |
engine = pyttsx3.init()
|
172 |
|
173 |
-
# Configurar la voz en espa帽ol (ajusta el 铆ndice o usa el id de la voz)
|
174 |
voices = engine.getProperty('voices')
|
175 |
for voice in voices:
|
176 |
if 'Spanish' in voice.name or 'Espa帽ol' in voice.name:
|
@@ -179,24 +181,23 @@ class MentalHealthChatbot:
|
|
179 |
else:
|
180 |
self.logger.warning("No se encontr贸 una voz en espa帽ol. Usando la voz predeterminada.")
|
181 |
|
182 |
-
# Configurar la velocidad del habla si es necesario
|
183 |
rate = engine.getProperty('rate')
|
184 |
-
engine.setProperty('rate', rate - 50)
|
185 |
|
186 |
-
# Guardar el audio en el archivo especificado
|
187 |
engine.save_to_file(text, file_path)
|
188 |
engine.runAndWait()
|
189 |
|
190 |
self.logger.info(f"Audio generado y guardado en {file_path}")
|
191 |
|
192 |
-
#
|
193 |
-
return
|
|
|
194 |
except Exception as e:
|
195 |
self.logger.error(f"Error al generar audio: {str(e)}")
|
196 |
return None
|
197 |
|
198 |
def update_conversation_history(self, user_input: str, response: str, emotion: str):
|
199 |
-
"""Actualiza el historial de conversaci贸n."""
|
200 |
try:
|
201 |
self.conversation_history.append({
|
202 |
'user_input': user_input,
|
@@ -205,7 +206,6 @@ class MentalHealthChatbot:
|
|
205 |
'timestamp': datetime.now().isoformat()
|
206 |
})
|
207 |
|
208 |
-
# Mantener solo las 煤ltimas 10 conversaciones
|
209 |
if len(self.conversation_history) > 10:
|
210 |
self.conversation_history.pop(0)
|
211 |
|
@@ -214,9 +214,10 @@ class MentalHealthChatbot:
|
|
214 |
self.logger.error(f"Error al actualizar el historial de conversaci贸n: {str(e)}")
|
215 |
|
216 |
def save_conversation_history(self):
|
217 |
-
"""Guarda el historial de conversaci贸n en un archivo."""
|
218 |
try:
|
219 |
-
|
|
|
220 |
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
221 |
|
222 |
with open(filename, 'w', encoding='utf-8') as f:
|
@@ -224,4 +225,4 @@ class MentalHealthChatbot:
|
|
224 |
|
225 |
self.logger.info(f"Historial de conversaci贸n guardado en {filename}")
|
226 |
except Exception as e:
|
227 |
-
self.logger.error(f"Error al guardar el historial: {str(e)}")
|
|
|
21 |
# Configuraci贸n del logging
|
22 |
self.logger = logging.getLogger(__name__)
|
23 |
self.logger.setLevel(logging.INFO)
|
24 |
+
|
25 |
+
# Archivo de log en /tmp
|
26 |
+
handler = logging.FileHandler('/tmp/chatbot.log')
|
27 |
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
28 |
handler.setFormatter(formatter)
|
29 |
if not self.logger.handlers:
|
30 |
self.logger.addHandler(handler)
|
31 |
|
32 |
+
# Rutas de carpetas en /tmp para evitar permisos de solo lectura en /app
|
33 |
+
self.conversations_dir = "/tmp/conversations"
|
34 |
+
self.audio_dir = "/tmp/audio"
|
35 |
+
|
36 |
try:
|
37 |
self.logger.info("Cargando el tokenizador y el modelo BERT fine-tuned...")
|
38 |
|
39 |
+
# Crear carpeta de conversaciones en /tmp
|
40 |
+
os.makedirs(self.conversations_dir, exist_ok=True)
|
41 |
|
42 |
self.tokenizer = BertTokenizer.from_pretrained(model_path)
|
43 |
self.model = BertForSequenceClassification.from_pretrained(model_path).to(self.device)
|
|
|
90 |
|
91 |
def get_emotion_prediction(self, text: str) -> Tuple[str, float]:
|
92 |
"""Predice la emoci贸n del texto usando el modelo fine-tuned."""
|
93 |
+
emotion_labels = [
|
94 |
+
'FELICIDAD', 'NEUTRAL', 'DEPRESI脫N', 'ANSIEDAD', 'ESTR脡S',
|
95 |
+
'EMERGENCIA', 'CONFUSI脫N', 'IRA', 'MIEDO', 'SORPRESA', 'DISGUSTO'
|
96 |
+
]
|
97 |
|
98 |
try:
|
99 |
inputs = self.tokenizer.encode_plus(
|
|
|
122 |
def generate_response(self, user_input: str) -> Dict[str, Any]:
|
123 |
"""Genera una respuesta basada en el input del usuario."""
|
124 |
try:
|
|
|
125 |
processed_text = self.preprocess_text(user_input)
|
126 |
self.logger.info(f"Texto procesado: {processed_text}")
|
127 |
|
|
|
128 |
if self.detect_emergency(processed_text):
|
129 |
emotion = 'EMERGENCIA'
|
130 |
confidence = 1.0
|
131 |
self.logger.info("Emergencia detectada en el mensaje del usuario.")
|
132 |
else:
|
|
|
133 |
emotion, confidence = self.get_emotion_prediction(processed_text)
|
134 |
|
|
|
135 |
responses = self.responses.get(emotion, self.responses.get('CONFUSI脫N', ["Lo siento, no he entendido tu mensaje."]))
|
|
|
136 |
response = np.random.choice(responses)
|
137 |
self.logger.info(f"Respuesta seleccionada: {response}")
|
138 |
|
|
|
139 |
audio_path = self.generate_audio(response)
|
140 |
|
|
|
141 |
self.update_conversation_history(user_input, response, emotion)
|
|
|
|
|
142 |
self.save_conversation_history()
|
143 |
|
144 |
return {
|
|
|
160 |
}
|
161 |
|
162 |
def generate_audio(self, text: str) -> str:
|
163 |
+
"""
|
164 |
+
Genera el audio para la respuesta y devuelve una ruta local.
|
165 |
+
Nota: Si quieres servir este audio v铆a HTTP,
|
166 |
+
necesitar谩s un endpoint que lo sirva desde /tmp/audio.
|
167 |
+
"""
|
168 |
try:
|
169 |
filename = f"response_{datetime.now().strftime('%Y%m%d_%H%M%S_%f')}.mp3"
|
170 |
+
# Guardar audios en /tmp/audio
|
171 |
+
file_path = os.path.join(self.audio_dir, filename)
|
172 |
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
173 |
|
174 |
engine = pyttsx3.init()
|
175 |
|
|
|
176 |
voices = engine.getProperty('voices')
|
177 |
for voice in voices:
|
178 |
if 'Spanish' in voice.name or 'Espa帽ol' in voice.name:
|
|
|
181 |
else:
|
182 |
self.logger.warning("No se encontr贸 una voz en espa帽ol. Usando la voz predeterminada.")
|
183 |
|
|
|
184 |
rate = engine.getProperty('rate')
|
185 |
+
engine.setProperty('rate', rate - 50)
|
186 |
|
|
|
187 |
engine.save_to_file(text, file_path)
|
188 |
engine.runAndWait()
|
189 |
|
190 |
self.logger.info(f"Audio generado y guardado en {file_path}")
|
191 |
|
192 |
+
# Devolvemos la ruta local en /tmp/audio
|
193 |
+
return file_path
|
194 |
+
|
195 |
except Exception as e:
|
196 |
self.logger.error(f"Error al generar audio: {str(e)}")
|
197 |
return None
|
198 |
|
199 |
def update_conversation_history(self, user_input: str, response: str, emotion: str):
|
200 |
+
"""Actualiza el historial de conversaci贸n en memoria."""
|
201 |
try:
|
202 |
self.conversation_history.append({
|
203 |
'user_input': user_input,
|
|
|
206 |
'timestamp': datetime.now().isoformat()
|
207 |
})
|
208 |
|
|
|
209 |
if len(self.conversation_history) > 10:
|
210 |
self.conversation_history.pop(0)
|
211 |
|
|
|
214 |
self.logger.error(f"Error al actualizar el historial de conversaci贸n: {str(e)}")
|
215 |
|
216 |
def save_conversation_history(self):
|
217 |
+
"""Guarda el historial de conversaci贸n en un archivo dentro de /tmp."""
|
218 |
try:
|
219 |
+
# Guardamos en /tmp/conversations
|
220 |
+
filename = f"{self.conversations_dir}/chat_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
221 |
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
222 |
|
223 |
with open(filename, 'w', encoding='utf-8') as f:
|
|
|
225 |
|
226 |
self.logger.info(f"Historial de conversaci贸n guardado en {filename}")
|
227 |
except Exception as e:
|
228 |
+
self.logger.error(f"Error al guardar el historial: {str(e)}")
|