diff --git a/resume_end_call.py b/resume_end_call.py new file mode 100644 index 0000000..d9a4119 --- /dev/null +++ b/resume_end_call.py @@ -0,0 +1,205 @@ +import os +import sys +import pymysql +import tempfile +from pydub import AudioSegment +import speech_recognition as sr +import anthropic + +def consultar_claude(text): + client = anthropic.Anthropic(api_key='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') + message = client.messages.create( + #model="claude-3-5-haiku-20241022", + model = "claude-3-5-sonnet-20241022", + max_tokens=1000, + temperature=0, + system=( + "A continuación te paso el texto de una llamada y necesito un resumen completo que incluya toda la información proporcionada por el cliente. " + "El resumen debe ser detallado y abarcar todos los aspectos relevantes, como el incidente reportado, cualquier comentario comercial, " + "y los datos del cliente. El tema debe ser separado en dos columnas: una para el 'TEMA', todo el contenido de esta columna debe ir en negrita, para el 'RESUMEN'. Al final, debes incluir una fila " + "con los datos que el cliente suministró, tales como su nombre, cédula y placa. Dame la respuesta en formato HTML con una tabla que tenga estas columnas: " + "'TEMA' y 'RESUMEN'." + ), + messages=[ + { + "role": "user", + "content": [{"type": "text", "text": text}] + } + ] + ) + respuesta_claude = "".join([msg.text for msg in message.content]) + + # Procesar para agregar la clase TEMA a todas las celdas correspondientes + respuesta_claude = respuesta_claude.replace("", "") + return respuesta_claude + + +def get_filename_from_db(recording_id): + connection = pymysql.connect( + host='sapian-ccdb-clients-sapian.service.dc-k8s-voe.consul', + user='cctel', + password='PpteK0GYyi', + database='asterisk' + ) + try: + with connection.cursor() as cursor: + query = "SELECT filename FROM recording_log WHERE recording_id = %s" + cursor.execute(query, (recording_id,)) + result = cursor.fetchone() + if result: + return result[0] + else: + raise ValueError("No se encontró la grabación con el recording_id proporcionado.") + finally: + connection.close() + +def split_audio(file_path, output_folder): + audio = AudioSegment.from_file(file_path) + duration = len(audio) # Duration in milliseconds + chunk_duration = 60 * 1000 # 1 minute in milliseconds + chunks = [] + for i in range(0, duration, chunk_duration): + chunk = audio[i:i + chunk_duration] + chunk_name = os.path.join(output_folder, f"chunk_{i//chunk_duration + 1}.wav") + chunk.export(chunk_name, format="wav") + chunks.append(chunk_name) + return chunks + +def transcribe_audio_chunks(chunks): + recognizer = sr.Recognizer() + transcription = [] + for idx, chunk in enumerate(chunks, 1): + with sr.AudioFile(chunk) as source: + audio_data = recognizer.record(source) + try: + text = recognizer.recognize_google(audio_data, language="es-ES") + transcription.append(f"Fragmento {idx}: {text}") + except sr.UnknownValueError: + transcription.append(f"Fragmento {idx}: No se pudo reconocer el audio") + except sr.RequestError as e: + transcription.append(f"Fragmento {idx}: Error en el servicio de reconocimiento ({e})") + return "\n".join(transcription) + + +def generate_html_summary(summary, output_path): + # Define todo el CSS en una sola variable, incluyendo el estilo para las dos primeras filas + css_styles = """ + body { + font-family: Arial, sans-serif; + background-color: #f4f4f4; + margin: 0; + padding: 0; + text-align: center; + position: relative; + } + h1 { + font-weight: bold; + color: #4CAF50; + margin-top: 50px; + } + p { + font-size: 18px; + line-height: 1.6; + max-width: 800px; + margin: 20px auto; + text-align: justify; + } + .logo { + position: absolute; + top: 10px; + right: 20px; + width: 150px; + height: auto; + } + table { + width: 100%; + border-collapse: collapse; + margin: 20px 0px; + font-family: Arial, sans-serif; + background-color: white; + border: 2px solid #004d40; + } + th, td { + padding: 12px; + text-align: center; + border: 1px solid #ddd; + } + th { + background-color: #004d40ff; + color: white; + font-weight: bold; + } + td.TEMA { + font-weight: bold; + } + td.resumen { + font-weight: normal; + } + tr:nth-child(1){ + background-color: #4CAF50; /* Verde para las dos primeras filas */ + color: white; /* Texto en blanco para contraste */ + } + tr:nth-child(even):not(:nth-child(1)):not(:nth-child(2)) { + background-color: white; + } + tr:hover { + background-color: #ddd; + } + """ + + # Genera el contenido HTML + html_content = f""" + + + +Resumen de Llamada + + + + +

Resumen de Llamada

+ + {summary} +
+ + + """ + # Escribir el archivo HTML en el directorio deseado + with open(output_path, "w") as file: + file.write(html_content) + + +def main(): + if len(sys.argv) != 2: + print("Uso: python script.py ") + sys.exit(1) + + recording_id = sys.argv[1] + + try: + filename = get_filename_from_db(recording_id) + audio_path = f"/var/spool/asterisk/monitor/{filename}"+"-in.WAV" + + if not os.path.exists(audio_path): + raise FileNotFoundError(f"No se encontró la grabación en la ruta: {audio_path}") + + temp_dir = tempfile.gettempdir() + output_folder = os.path.join(temp_dir, "audio_chunks") + os.makedirs(output_folder, exist_ok=True) + + chunks = split_audio(audio_path, output_folder) + transcription = transcribe_audio_chunks(chunks) + resumen = consultar_claude(transcription) + + output_html = f"/var/www/html/resumen_{recording_id}.html" + generate_html_summary(resumen, output_html) + + print(f"Proceso completado. Resumen generado en: {output_html}") + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + main() +You have new mail in /var/spool/mail/root