You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
6.5 KiB
206 lines
6.5 KiB
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='T057Zwoq-LOmplU5cScZhU87pnLosLJBhnvBODl-Jw22nnL4av_7-74r4hNcW8VoTE9-if-xDFInehYZ-hsCXA-s1xZ3wAA')
|
|
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("<td>", "<td class='TEMA'>")
|
|
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"""
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Resumen de Llamada</title>
|
|
<style>
|
|
{css_styles}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<img src="logoSapian.jpeg" alt="Logo de la Empresa" class="logo">
|
|
<h1>Resumen de Llamada</h1>
|
|
<table>
|
|
{summary}
|
|
</table>
|
|
</body>
|
|
</html>
|
|
"""
|
|
# 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 <recording_id>")
|
|
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
|