06. CITAS AUTOMATICO

Crear la cita vía WhatsApp

¡Has llegado lejos! Desde la instalación de nuestro sistema de citas hasta conectarlo con la base de datos y habilitar las respuestas automáticas con ChatGPT, has recorrido un camino significativo en este curso. Luego, en nuestro último tutorial, exploramos cómo responder a los clientes a través de WhatsApp, dándole a nuestro sistema la capacidad de comunicarse en tiempo real en una plataforma popular y accesible. Ahora es el momento de unir todos estos componentes en nuestro tutorial final.

En esta última entrega de nuestro curso, titulada “Crear la cita vía WhatsApp”, vamos a culminar todo el proceso, dando a nuestro sistema la habilidad para no solo recibir y responder mensajes, sino también para concretar y agendar citas a través de WhatsApp. Esto implica la convergencia de todas las habilidades y conocimientos que has adquirido hasta ahora.

Estos son los puntos clave que abordaremos en este tutorial:

  1. Explicaremos cómo integrar todo lo que hemos construido hasta ahora para hacer que nuestro sistema de citas sea completamente funcional a través de WhatsApp.
  2. Analizaremos la lógica de programación necesaria para procesar la información del cliente y los mensajes entrantes para agendar citas.
  3. Te guiaremos a través de pruebas y escenarios en vivo para asegurarnos de que el sistema funciona de manera eficiente y sin problemas.

Al final de este tutorial, tendrás en tus manos un sistema de citas robusto, intuitivo y de vanguardia que funcionará a través de WhatsApp, proporcionando una plataforma familiar y accesible para tus clientes. Esta implementación mejorará la eficiencia de tu servicio, aumentará la satisfacción del cliente y te posicionará a la vanguardia en tu sector.

Nos entusiasma compartir esta última etapa contigo. ¡Vamos a dar este último paso juntos y hacer que tu sistema de citas sea todo un éxito! ¡Vamos a ello!

Configurar horario

Vamos a Sistema / Configuración Y colocamos nuestras fechas de apertura y cierre

En chatgpt.php agregamos este código

$fechaCita=creaCita($cliente,$telefono, $edad, $especialidad, $sintomas);

De tal suerte que nuestro codigo quedaria asi:

<?php
function preguntaChatgpt($system, $pregunta, $telefonoCliente,$listaCategorias){
    require "config.php";
    $config = new Config();
    $apiKey = $config->apiKeyChatgpt;
    $telefono = str_replace("521", "52", $telefonoCliente);
    //API KEY DE CHATGPT
    global $conn;
    // Consulta SQL para obtener las conversaciones anteriores
    $query = "SELECT mensaje_recibido, mensaje_enviado 
    FROM kimai2_registro 
    WHERE telefono_wa = ? 
    AND fecha_hora > DATE_SUB(NOW(), INTERVAL 2 HOUR)
    -- AND cita_creada = 0
    ORDER BY fecha_hora ASC";
    $stmtMensajes = $conn->prepare($query);
    // Vincula el parámetro "telefono" a la consulta SQL
    $stmtMensajes->bind_param('s', $telefono);
    // Ejecuta la consulta
    $stmtMensajes->execute();
    // Obtiene el resultado
    $result = $stmtMensajes->get_result();
    // Construye el array de mensajes anteriores
    $messages = array();
    while ($row = $result->fetch_assoc()) {
        $messages[] = array("role" => "user", "content" => $row['mensaje_recibido']);
        $messages[] = array("role" => "assistant", "content" => $row['mensaje_enviado']);
    }
    // Agrega el mensaje del sistema y la pregunta actual del usuario
    array_unshift($messages, array("role" => "system", "content" => $system));
    $messages[] = array("role" => "user", "content" => $pregunta);
    //INICIAMOS LA CONSULTA DE CURL
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.openai.com/v1/chat/completions');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer '.$apiKey,
        'Content-Type: application/json',
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, 
    json_encode(array(
        "model" => "gpt-3.5-turbo",
        "messages" => $messages,
        "temperature" => 0
    )));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($ch);
    // Obtiene información de los encabezados de la respuesta
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $headerSize);
    curl_close($ch);
    // Decodificar el JSON
    $data = json_decode($header, true);
    // Obtener el valor de 'total_tokens'
    $totalTokens = $data['usage']['total_tokens'];
    curl_close($ch);
    $decoded_json = json_decode($response, false);
    //RETORNAMOS LA RESPUESTA QUE EXTRAEMOS DEL JSON
    $respuesta=$decoded_json->choices[0]->message->content;
    $respuesta = str_replace('"', '-', $respuesta);
    $respuesta = str_replace('\"', '-', $respuesta);
    $respuesta = str_replace('\\"', '-', $respuesta);
    $respuesta=stripcslashes($respuesta);
    if (strpos($respuesta, '||') !== false) {
        $respuestaDividida = explode('||', $respuesta);
        // Ahora, cada elemento del array $respuestaDividida contiene una parte de la respuesta
        $cliente = trim($respuestaDividida[1]);
        $cliente=$cliente." ".$telefono;
        $edad = trim($respuestaDividida[2]);
        $especialidad = trim($respuestaDividida[3]);
        $especialidad=quitar_acentos($especialidad);
        $listaCategoriasArray = explode(",", $listaCategorias);
        // quitar acentos
        foreach($listaCategoriasArray as $categoria){
            if(strpos($especialidad, $categoria) !== false){
                $especialidad = $categoria;
                break;
            }
        }
        //Si $especialidad esta vacio poner "Diagnostico"
        if($especialidad==""){
            $especialidad="Medico general";
        }
        $sintomas = trim($respuestaDividida[4]);
        require_once('crearCita.php');
        $fechaCita=creaCita($cliente,$telefono, $edad, $especialidad, $sintomas);
        global $textoCita;
        //a $fechaCita darle formato dia mes año hora y minuto
        
        $fechaCita = strtotime($fechaCita);  // Convierte la fecha en un timestamp de Unix
        setlocale(LC_TIME, 'es_ES.UTF-8');
        $fechaFormateada = strftime("%A %d de %B del %Y a las %H:%M", $fechaCita);
        $fechaFormateada=translateDayInText($fechaFormateada);
        $respuesta = $textoCita." ".$fechaFormateada.", en el transcurso del dia un experto en '".$especialidad."' se pondrá en contacto con usted para confirmar la cita y darle seguimiento.";
        //$respuesta
    }

    //obtener la fecha y hora en string
    $fecha = date("Y-m-d H:i:s");
    file_put_contents('responseChatgpt.txt', $fecha."-".$response."\n".$respuesta);
    return $respuesta;
           
}
function quitar_acentos($cadena){
    $originales = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûýýþÿ';
    $modificadas = 'aaaaaaaceeeeiiiidnoooooouuuuybsaaaaaaaceeeeiiiidnoooooouuuyyby';
    $cadena = utf8_decode($cadena);
    $cadena = strtr($cadena, utf8_decode($originales), $modificadas);
    return utf8_encode($cadena);
}
function translateDayInText($text) {
    // Definir la matriz de traducción
    $translationArray = array(
        "Monday" => "Lunes",
        "Tuesday" => "Martes",
        "Wednesday" => "Miércoles",
        "Thursday" => "Jueves",
        "Friday" => "Viernes",
        "Saturday" => "Sábado",
        "Sunday" => "Domingo"
    );
    
    // Dividir el texto en palabras
    $words = explode(" ", $text);

    // Verificar cada palabra
    foreach ($words as $key => $word) {
        // Si la palabra es un día de la semana en inglés, traducirlo
        if (isset($translationArray[$word])) {
            $words[$key] = $translationArray[$word];
        }
    }
    
    // Unir las palabras de nuevo en un texto
    $text = implode(" ", $words);
    
    return $text;
}

Creamos el archivo crearCita.php

Este archivo se va encargar de crear la cita en kimai

<?php
function creaCita($cliente, $telefono, $proyecto, $usuario, $descripcion)
{
    try {
        global $conn;
        $cliente = str_replace("Cliente: ", "", $cliente);
        $proyecto = str_replace("Datos del auto: ", "", $proyecto);

        // Obtén las horas de inicio y fin del negocio
        $sql = "SELECT value FROM kimai2_configuration WHERE name = 'calendar.businessHours.begin'";
        $result = $conn->query($sql);
        $row = $result->fetch_assoc();
        $businessHoursBegin = new DateTime($row['value']);

        $sql = "SELECT value FROM kimai2_configuration WHERE name = 'calendar.businessHours.end'";
        $result = $conn->query($sql);
        $row = $result->fetch_assoc();
        $businessHoursEnd = new DateTime($row['value']);

        // Verifica si el cliente ya existe
        $sql = "SELECT id FROM `kimai2_customers` WHERE `phone` = '$telefono'";
        $result = $conn->query($sql);
        $clienteRow = $result->fetch_assoc();

        if ($clienteRow) {
            // Si el cliente existe, toma el ID existente
            $client_id = $clienteRow['id'];
        } else {
            // Si el cliente no existe, crea uno nuevo
            $sql = "INSERT INTO `kimai2_customers` (`name`, `phone`, `visible`, `country`, `currency`, `timezone`) VALUES ('$cliente', '$telefono', '1', 'ES', 'EUR', 'Atlantic/Canary')";
            $conn->query($sql);
            $client_id = $conn->insert_id;  // Toma el ID del cliente recién creado
        }

        // Verifica si el proyecto ya existe para este cliente
        $sql = "SELECT id FROM `kimai2_projects` WHERE `customer_id` = $client_id LIMIT 1";
        $result = $conn->query($sql);
        $proyectoRow = $result->fetch_assoc();

        if ($proyectoRow) {
            // Si el proyecto existe, toma el ID existente
            $project_id = $proyectoRow['id'];
        } else {
            // Si el proyecto no existe, crea uno nuevo
            $sql = "INSERT INTO `kimai2_projects` (`customer_id`,`name`, `visible`) VALUES ('$client_id', '$proyecto', '1')";
            $conn->query($sql);
            $project_id = $conn->insert_id;  // Toma el ID del proyecto recién creado
        }

        // Determina la cantidad de días y minutos basados en el tipo de usuario
        $diasAdelanto = 0;
        $minutos = 0;
        switch ($usuario) {
            case 'Medico general':
                $diasAdelanto = 1;
                $minutos = 60;
                break;
            case 'Cardiologia':
                $diasAdelanto = 1;
                $minutos = 60;
                break;
            case 'Pediatria':
                $diasAdelanto = 2;
                $minutos = 60;
                break;
            default:
                $usuario='Medico general';
                $diasAdelanto = 2;
                $minutos = 60;
        }

        // Obtiene la fecha de hoy más el adelanto de días
        $fechaAdelantada = date('Y-m-d', strtotime("+$diasAdelanto days"));

        $start_time = $fechaAdelantada . ' ' . $businessHoursBegin->format('H:i:s');
        $segundos = $minutos * 60;  // Segundos de duración de la cita
        $end_time = date('Y-m-d H:i:s', strtotime($start_time) + $segundos);

        // Convertir a objetos DateTime para facilitar la comparación
        $startTime = new DateTime($start_time);
        $endTime = new DateTime($end_time);

        // Obtener el ID del usuario basado en el alias de usuario
        $sqlIdUser = "SELECT id FROM kimai2_users WHERE alias = '$usuario'";
        $resultIdUser = $conn->query($sqlIdUser);
        $user = $resultIdUser->fetch_assoc();
        $user_id = $user['id'];

        // Revisar cada intervalo de tiempo posible para la cita dentro del horario de trabajo
        while (true) {
            // Asegurarse que sea un día de la semana
            while ($startTime->format('N') >= 6) {  // Saltar sábados y domingos
                $startTime = getNextBusinessDay($startTime);
                $startTime->setTime($businessHoursBegin->format('H'), $businessHoursBegin->format('i'), $businessHoursBegin->format('s'));  // Configurar al inicio del horario de trabajo
                $endTime = clone $startTime;
                $endTime->modify('+' . $segundos . ' seconds');
            }

            // Comprobar si ya existe una cita para este usuario y este intervalo de tiempo
            $start_time = $startTime->format('Y-m-d H:i:s');
            $end_time = $endTime->format('Y-m-d H:i:s');

            // Si la cita termina después del horario de trabajo, configurar al inicio del próximo día hábil
            $businessHoursEnd->setDate($endTime->format('Y'), $endTime->format('m'), $endTime->format('d'));
            if ($endTime > $businessHoursEnd) {
                $startTime = getNextBusinessDay($startTime);
                $startTime->setTime($businessHoursBegin->format('H'), $businessHoursBegin->format('i'), $businessHoursBegin->format('s'));  // Configurar al inicio del horario de trabajo
                $endTime = clone $startTime;
                $endTime->modify('+' . $segundos . ' seconds');
                continue;  // Volver al inicio del ciclo
            }

            $sql = "SELECT * FROM `kimai2_timesheet` WHERE `user` = $user_id AND ((`start_time` >= '$start_time' AND `start_time` < '$end_time') OR (`end_time` > '$start_time' AND `end_time` <= '$end_time'))";
            $result = $conn->query($sql);

            if ($result->num_rows > 0) {
                // Si ya existe una cita en este intervalo de tiempo, mover el inicio y fin de la cita al próximo intervalo posible
                $startTime->modify("+{$minutos} minutes");
                $endTime->modify("+{$minutos} minutes");
            } else {
                // Si no hay ninguna cita en este intervalo de tiempo, es un intervalo válido para la cita
                break;
            }
        }

        // Obtener el ID del último registro con cita_creada=1
        $sql = "SELECT MAX(id) AS id FROM kimai2_registro WHERE cita_creada = 1";
        $resultCita = $conn->query($sql);
        $rowCita= $resultCita->fetch_assoc();
        $lastId = $rowCita['id'];

        // Si no se encontró ningún registro con cita_creada=1, seleccionar el primer registro
        if ($lastId === null) {
            $sql = "SELECT * FROM kimai2_registro ORDER BY id LIMIT 1";
        } else {
            // Seleccionar los registros a partir del registro con ID que es uno mayor que el último ID con cita_creada=1
            $sql = "SELECT * FROM kimai2_registro WHERE id > $lastId ORDER BY id";
        }

        $resultRegistro = $conn->query($sql);
        $descripcion=$descripcion."\n CONVERSACION \n";
        // Procesar el resultado
        while ($rowRegistro = $resultRegistro->fetch_assoc()) {
            $descripcion=$descripcion. "Mensaje Recibido: {$rowRegistro['mensaje_recibido']}\n";
            $descripcion=$descripcion. "Mensaje Enviado: {$rowRegistro['mensaje_enviado']}\n";
            $descripcion=$descripcion. "-------------------------\n";
        }
        $descripcion = str_replace("'", "-", $descripcion);
        
        $sql = "INSERT INTO `kimai2_timesheet` 
            (`user`, `activity_id`, `project_id`, `start_time`, `end_time`, `duration`, `description`, `rate`, `hourly_rate`, `timezone`, `internal_rate`, `modified_at`, `date_tz`) VALUES 
            ('$user_id', '1', '$project_id', '$start_time', '$end_time', '$segundos', '" . $descripcion . "', '0', '0', 'Atlantic/Canary', '0', now(), now())";

        $conn->query($sql);
        
        return $start_time;
    } catch (Exception $e) {
        echo 'Excepción capturada: ',  $e->getMessage(), "\n";
        return null;
    }
}

function getNextBusinessDay($date)
{
    do {
        $date->modify('+1 day');
    } while ($date->format('N') >= 6);  // Saltar sábados y domingos
    return $date;
}

Listo hemos terminado, por ultimo te voy a dejar todos los códigos

index.php

<?php
/*
 * VERIFICACION DEL WEBHOOK
*/
//TOQUEN QUE QUERRAMOS PONER 
$token = 'HolaNovato';
//RETO QUE RECIBIREMOS DE FACEBOOK
$palabraReto = $_GET['hub_challenge'];
//TOQUEN DE VERIFICACION QUE RECIBIREMOS DE FACEBOOK
$tokenVerificacion = $_GET['hub_verify_token'];
//SI EL TOKEN QUE GENERAMOS ES EL MISMO QUE NOS ENVIA FACEBOOK RETORNAMOS EL RETO PARA VALIDAR QUE SOMOS NOSOTROS
if ($token === $tokenVerificacion) {
    echo $palabraReto;
    exit;
}
$textoCita="He creado su cita para el dia";
/*
 * RECEPCION DE MENSAJES
 */
//LEEMOS LOS DATOS ENVIADOS POR WHATSAPP
$respuesta = file_get_contents("php://input");
//CONVERTIMOS EL JSON EN ARRAY DE PHP
$respuesta = json_decode($respuesta, true);
//EXTRAEMOS EL MENSAJE DEL ARRAY
$mensaje = $respuesta['entry'][0]['changes'][0]['value']['messages'][0]['text']['body'];
//EXTRAEMOS EL TELEFONO DEL ARRAY
$telefonoCliente = $respuesta['entry'][0]['changes'][0]['value']['messages'][0]['from'];
//EXTRAEMOS EL ID DE WHATSAPP DEL ARRAY
$id = $respuesta['entry'][0]['changes'][0]['value']['messages'][0]['id'];
//EXTRAEMOS EL TIEMPO DE WHATSAPP DEL ARRAY
$timestamp = $respuesta['entry'][0]['changes'][0]['value']['messages'][0]['timestamp'];
//SI HAY UN MENSAJE
if ($mensaje != null) {
    $pregunta = $mensaje;
    require_once("conexion.php");
    // Prepara la consulta SQL
    $queryCompania = 'SELECT company, address, contact FROM kimai2_invoice_templates WHERE id = ?';
    $stmtCompania = $conn->prepare($queryCompania);
    // Vincula el parámetro "id" a la consulta SQL
    $id_inv = 1;
    $stmtCompania->bind_param('i', $id_inv);
    // Ejecuta la consulta
    $stmtCompania->execute();
    // Obtiene el resultado
    $resultCompania = $stmtCompania->get_result();
    // Obtiene los datos del registro
    $rowCompania = $resultCompania->fetch_assoc();
    // Prepara la consulta SQL
    // Crea la consulta SQL
    $queryCategoria = "SELECT alias FROM kimai2_users WHERE enabled = 1 AND id != 1";
    // Prepara la consulta
    $stmtCategoria = $conn->prepare($queryCategoria);
    // Ejecuta la consulta
    $stmtCategoria->execute();
    // Obtiene el resultado
    $resultCategoria = $stmtCategoria->get_result();
    // Crea un array para guardar los alias
    $listaCategorias = "";
    // Recorre los resultados y añade cada alias al array
    while ($row = $resultCategoria->fetch_assoc()) {
        $listaCategorias = $listaCategorias.$row['alias'].",";
    }
    $listaCategorias = rtrim($listaCategorias, ",");
    $system="Hola, soy un asesor de Información de la clínica ".$rowCompania['company'].
    ", no proporciono citas pero genero reportes para que posteriormente un experto agende una cita, no doy recomendaciones para curar, recomiendo solo mi clínica y pido un dato a la vez.".
    " Mis tareas incluyen recibir información, escribir reportes y no hay necesidad de que el paciente lo sepa. Aquí está el procedimiento que sigo: ".
    "1. Primero, pido el nombre. ".
    "2. Luego, pido la edad. ".
    "3. Después, pregunto qué sintomas tiene y en base a las respuestas defino en cuál de estas especialidades cae: ".
    $listaCategorias.".".
    "Si no cae en ninguna especialidad colocarlo en Medico general.".
    "Una vez recolectada la información sobre los síntomas, no programo ninguna cita. En cambio, escribo un reporte con este formato: ".
    "||paciente||etapa_edad||especialidad||sintomas|| (reemplaza el contenido entre || por la información recolectada).".
    //"||cliente||datos_auto||categoria_falla||descripcion_falla|| (reemplaza el contenido entre || por la información recolectada).".
    "Es vital que siempre que detecte sintomas, escriba el reporte en el formato mencionado para que un experto agende una cita. ".
    "Si el paciente me pide una cita le debo escribir el reporte con el formato mencionado. ".
    "Importante: No invento ni añado ninguna información que no se me haya proporcionado. Todo mi trabajo se basa en los datos que recibo.";
    "Solo si me lo piden doy informacion de la empresa, Nombre de la empresa: " . $rowCompania['company'] . ", Ubicación: " . $rowCompania['address'] . " " . $rowCompania['contact'] . ". ";

    require_once "chatgpt.php";
    $respuesta = preguntaChatgpt($system, $pregunta, $telefonoCliente,$listaCategorias);
    //ESCRIBIMOS LA RESPUESTA
    file_put_contents("respuesta.txt", $respuesta);
    require_once "whatsapp.php";
    //ENVIAMOS LA RESPUESTA VIA WHATSAPP
    enviar($mensaje, $respuesta, $id, $timestamp, $telefonoCliente);

}

conexion.php

<?php
require __DIR__ . '/../../vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../..');
$dotenv->load();
$databaseUrl = $_ENV['DATABASE_URL'];
$components = parse_url($databaseUrl);
$dbName = ltrim($components['path'], '/');
// Crear la conexión
$conn = new mysqli($components['host'], $components['user'], $components['pass'], $dbName);
if ($conn->connect_error) {
    die("Error de conexión: " . $conn->connect_error);
}

config.php

<?php
class Config {
    public $apiKeyChatgpt;
    public $tokenWa;
    public $telefonoIDWa;
    public $remoto;

    public function __construct() {
        $remoto=true;
        if ($remoto) {
            // Coloca estos valores si remoto es true
            $this->apiKeyChatgpt = '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';
            $this->tokenWa = 'EAANIQCCaMQIBAM1cIHPp640kaa6fbVXNxyoiGEAQYubPdlI0PsmfTEiZBWZCENX1ZAyGDIC3IHiu3meSGiDU6tTg2Kyam7yjOPVXZAyYpNkrB4byIldswdGmwv1nAZABD3MaO2a5nD4TPe3Dhgbbpd9AGpzylWyrhp0ZBqKFNIvkcwKh8t87QlzZC34fsmpNlni1Eu9slLLRwZDZD';
            $this->telefonoIDWa = '116907067953774';
        } else {
            // Coloca estos valores si remoto es false
            $this->apiKeyChatgpt = 'otro_valor';
            $this->tokenWa = 'otro_valor';
            $this->telefonoIDWa = 'otro_valor';
        }
    }
}

chatgpt.php

<?php
function preguntaChatgpt($system, $pregunta, $telefonoCliente,$listaCategorias){
    require "config.php";
    $config = new Config();
    $apiKey = $config->apiKeyChatgpt;
    $telefono = str_replace("521", "52", $telefonoCliente);
    //API KEY DE CHATGPT
    global $conn;
    // Consulta SQL para obtener las conversaciones anteriores
    $query = "SELECT mensaje_recibido, mensaje_enviado 
    FROM kimai2_registro 
    WHERE telefono_wa = ? 
    AND fecha_hora > DATE_SUB(NOW(), INTERVAL 2 HOUR)
    -- AND cita_creada = 0
    ORDER BY fecha_hora ASC";
    $stmtMensajes = $conn->prepare($query);
    // Vincula el parámetro "telefono" a la consulta SQL
    $stmtMensajes->bind_param('s', $telefono);
    // Ejecuta la consulta
    $stmtMensajes->execute();
    // Obtiene el resultado
    $result = $stmtMensajes->get_result();
    // Construye el array de mensajes anteriores
    $messages = array();
    while ($row = $result->fetch_assoc()) {
        $messages[] = array("role" => "user", "content" => $row['mensaje_recibido']);
        $messages[] = array("role" => "assistant", "content" => $row['mensaje_enviado']);
    }
    // Agrega el mensaje del sistema y la pregunta actual del usuario
    array_unshift($messages, array("role" => "system", "content" => $system));
    $messages[] = array("role" => "user", "content" => $pregunta);
    //INICIAMOS LA CONSULTA DE CURL
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.openai.com/v1/chat/completions');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer '.$apiKey,
        'Content-Type: application/json',
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, 
    json_encode(array(
        "model" => "gpt-3.5-turbo",
        "messages" => $messages,
        "temperature" => 0
    )));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($ch);
    // Obtiene información de los encabezados de la respuesta
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $headerSize);
    curl_close($ch);
    // Decodificar el JSON
    $data = json_decode($header, true);
    // Obtener el valor de 'total_tokens'
    $totalTokens = $data['usage']['total_tokens'];
    curl_close($ch);
    $decoded_json = json_decode($response, false);
    //RETORNAMOS LA RESPUESTA QUE EXTRAEMOS DEL JSON
    $respuesta=$decoded_json->choices[0]->message->content;
    $respuesta = str_replace('"', '-', $respuesta);
    $respuesta = str_replace('\"', '-', $respuesta);
    $respuesta = str_replace('\\"', '-', $respuesta);
    $respuesta=stripcslashes($respuesta);
    if (strpos($respuesta, '||') !== false) {
        $respuestaDividida = explode('||', $respuesta);
        // Ahora, cada elemento del array $respuestaDividida contiene una parte de la respuesta
        $cliente = trim($respuestaDividida[1]);
        $cliente=$cliente." ".$telefono;
        $edad = trim($respuestaDividida[2]);
        $especialidad = trim($respuestaDividida[3]);
        $especialidad=quitar_acentos($especialidad);
        $listaCategoriasArray = explode(",", $listaCategorias);
        // quitar acentos
        foreach($listaCategoriasArray as $categoria){
            if(strpos($especialidad, $categoria) !== false){
                $especialidad = $categoria;
                break;
            }
        }
        //Si $especialidad esta vacio poner "Diagnostico"
        if($especialidad==""){
            $especialidad="Medico general";
        }
        $sintomas = trim($respuestaDividida[4]);
        require_once('crearCita.php');
        $fechaCita=creaCita($cliente,$telefono, $edad, $especialidad, $sintomas);
        global $textoCita;
        //a $fechaCita darle formato dia mes año hora y minuto
        
        $fechaCita = strtotime($fechaCita);  // Convierte la fecha en un timestamp de Unix
        setlocale(LC_TIME, 'es_ES.UTF-8');
        $fechaFormateada = strftime("%A %d de %B del %Y a las %H:%M", $fechaCita);
        $fechaFormateada=translateDayInText($fechaFormateada);
        $respuesta = $textoCita." ".$fechaFormateada.", en el transcurso del dia un experto en '".$especialidad."' se pondrá en contacto con usted para confirmar la cita y darle seguimiento.";
        //$respuesta
    }

    //obtener la fecha y hora en string
    $fecha = date("Y-m-d H:i:s");
    file_put_contents('responseChatgpt.txt', $fecha."-".$response."\n".$respuesta);
    return $respuesta;
           
}
function quitar_acentos($cadena){
    $originales = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûýýþÿ';
    $modificadas = 'aaaaaaaceeeeiiiidnoooooouuuuybsaaaaaaaceeeeiiiidnoooooouuuyyby';
    $cadena = utf8_decode($cadena);
    $cadena = strtr($cadena, utf8_decode($originales), $modificadas);
    return utf8_encode($cadena);
}
function translateDayInText($text) {
    // Definir la matriz de traducción
    $translationArray = array(
        "Monday" => "Lunes",
        "Tuesday" => "Martes",
        "Wednesday" => "Miércoles",
        "Thursday" => "Jueves",
        "Friday" => "Viernes",
        "Saturday" => "Sábado",
        "Sunday" => "Domingo"
    );
    
    // Dividir el texto en palabras
    $words = explode(" ", $text);

    // Verificar cada palabra
    foreach ($words as $key => $word) {
        // Si la palabra es un día de la semana en inglés, traducirlo
        if (isset($translationArray[$word])) {
            $words[$key] = $translationArray[$word];
        }
    }
    
    // Unir las palabras de nuevo en un texto
    $text = implode(" ", $words);
    
    return $text;
}

whatsapp.php

<?php
//enviar.php
/*
 * RECIBIMOS LA RESPUESTA
*/
function enviar($recibido, $enviadoWa, $idWA, $timestamp, $telefonoCliente)
{
    global $conn;
    global $textoCita;
    //CONSULTAMOS TODOS LOS REGISTROS CON EL ID DEL MANSAJE
    $sqlCantidad = "SELECT count(id) AS cantidad FROM kimai2_registro WHERE id_wa='" . $idWA . "';";
    $resultCantidad = $conn->query($sqlCantidad);
    //OBTENEMOS LA CANTIDAD DE MENSAJES ENCONTRADOS (SI ES 0 LO REGISTRAMOS SI NO NO)
    $cantidad = 0;
    //SI LA CONSULTA ARROJA RESULTADOS
    if ($resultCantidad) {
        //OBTENEMOS EL PRIMER REGISTRO
        $rowCantidad = $resultCantidad->fetch_row();
        //OBTENEMOS LA CANTIDAD DE REGISTROS
        $cantidad = $rowCantidad[0];
    }
    //SI LA CANTIDAD DE REGISTROS ES 0 ENVIAMOS EL MENSAJE DE LO CONTRARIO NO LO ENVIAMOS PORQUE YA SE ENVIO
    if ($cantidad == 0) {
        $enviado = str_replace("\n", "", $enviadoWa);
        //TOKEN QUE NOS DA FACEBOOK
        $config = new Config();
        $token = $config->tokenWa;
        //NUESTRO TELEFONO
        $telefono = str_replace("521", "52", $telefonoCliente);
        //IDENTIFICADOR DE NÚMERO DE TELÉFONO
        $telefonoID = $config->telefonoIDWa;

        //URL A DONDE SE MANDARA EL MENSAJE
        $url = 'https://graph.facebook.com/v16.0/' . $telefonoID . '/messages';
        //CONFIGURACION DEL MENSAJE
        $mensaje = ''
            . '{'
            . '"messaging_product": "whatsapp", '
            . '"recipient_type": "individual",'
            . '"to": "' . $telefono . '", '
            . '"type": "text", '
            . '"text": '
            . '{'
            . '     "body":"' . $enviado . '",'
            . '     "preview_url": true, '
            . '} '
            . '}';
        //DECLARAMOS LAS CABECERAS
        $header = array("Authorization: Bearer " . $token, "Content-Type: application/json",);
        //INICIAMOS EL CURL
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $mensaje);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        //OBTENEMOS LA RESPUESTA DEL ENVIO DE INFORMACION
        $responseString = curl_exec($curl);
        $response = json_decode($responseString, true);
        $fecha = date("Y-m-d H:i:s");
        file_put_contents('responseWhatsapp.txt', $fecha . "-" . $responseString);
        //OBTENEMOS EL CODIGO DE LA RESPUESTA
        $status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        //CERRAMOS EL CURL
        curl_close($curl);
        global $textoCita;
        if (strpos($enviado, $textoCita) !== false) {
            $cita_creada = "1";
        } else {
            $cita_creada = "0";
        }
        try {
            //Cambiar el texto de la cita para que chatgpt no detecte que fue una cita
            $enviado = str_replace($textoCita, "Un asesor se pondrá en contacto con usted el día", $enviado);
            //INSERTAMOS LOS REGISTROS DEL ENVIO DEL WHATSAPP
            $sql = "INSERT INTO kimai2_registro 
        (mensaje_recibido, mensaje_enviado, id_wa, timestamp_wa, telefono_wa,cita_creada) 
        VALUES (?, ?, ?, ?, ?, ?)";
            $stmt = $conn->prepare($sql);
            $stmt->bind_param('ssssss', $recibido, $enviado, $idWA, $timestamp, $telefono, $cita_creada);
            $result = $stmt->execute();
            if ($result) {
                echo "El registro se insertó correctamente";
            } else {
                $error = $stmt->error;
                echo "Error al insertar el registro: " . $error;
            }
        } catch (Exception $e) {
            $error = $e->getMessage();
            echo "Error al insertar el registro: " . $error;
        }
    }
}

crearCita.php

<?php
function creaCita($cliente, $telefono, $proyecto, $usuario, $descripcion)
{
    try {
        global $conn;
        $cliente = str_replace("Cliente: ", "", $cliente);
        $proyecto = str_replace("Datos del auto: ", "", $proyecto);

        // Obtén las horas de inicio y fin del negocio
        $sql = "SELECT value FROM kimai2_configuration WHERE name = 'calendar.businessHours.begin'";
        $result = $conn->query($sql);
        $row = $result->fetch_assoc();
        $businessHoursBegin = new DateTime($row['value']);

        $sql = "SELECT value FROM kimai2_configuration WHERE name = 'calendar.businessHours.end'";
        $result = $conn->query($sql);
        $row = $result->fetch_assoc();
        $businessHoursEnd = new DateTime($row['value']);

        // Verifica si el cliente ya existe
        $sql = "SELECT id FROM `kimai2_customers` WHERE `phone` = '$telefono'";
        $result = $conn->query($sql);
        $clienteRow = $result->fetch_assoc();

        if ($clienteRow) {
            // Si el cliente existe, toma el ID existente
            $client_id = $clienteRow['id'];
        } else {
            // Si el cliente no existe, crea uno nuevo
            $sql = "INSERT INTO `kimai2_customers` (`name`, `phone`, `visible`, `country`, `currency`, `timezone`) VALUES ('$cliente', '$telefono', '1', 'ES', 'EUR', 'Atlantic/Canary')";
            $conn->query($sql);
            $client_id = $conn->insert_id;  // Toma el ID del cliente recién creado
        }

        // Verifica si el proyecto ya existe para este cliente
        $sql = "SELECT id FROM `kimai2_projects` WHERE `customer_id` = $client_id LIMIT 1";
        $result = $conn->query($sql);
        $proyectoRow = $result->fetch_assoc();

        if ($proyectoRow) {
            // Si el proyecto existe, toma el ID existente
            $project_id = $proyectoRow['id'];
        } else {
            // Si el proyecto no existe, crea uno nuevo
            $sql = "INSERT INTO `kimai2_projects` (`customer_id`,`name`, `visible`) VALUES ('$client_id', '$proyecto', '1')";
            $conn->query($sql);
            $project_id = $conn->insert_id;  // Toma el ID del proyecto recién creado
        }

        // Determina la cantidad de días y minutos basados en el tipo de usuario
        $diasAdelanto = 0;
        $minutos = 0;
        switch ($usuario) {
            case 'Medico general':
                $diasAdelanto = 1;
                $minutos = 60;
                break;
            case 'Cardiologia':
                $diasAdelanto = 1;
                $minutos = 60;
                break;
            case 'Pediatria':
                $diasAdelanto = 2;
                $minutos = 60;
                break;
            default:
                $usuario='Medico general';
                $diasAdelanto = 2;
                $minutos = 60;
        }

        // Obtiene la fecha de hoy más el adelanto de días
        $fechaAdelantada = date('Y-m-d', strtotime("+$diasAdelanto days"));

        $start_time = $fechaAdelantada . ' ' . $businessHoursBegin->format('H:i:s');
        $segundos = $minutos * 60;  // Segundos de duración de la cita
        $end_time = date('Y-m-d H:i:s', strtotime($start_time) + $segundos);

        // Convertir a objetos DateTime para facilitar la comparación
        $startTime = new DateTime($start_time);
        $endTime = new DateTime($end_time);

        // Obtener el ID del usuario basado en el alias de usuario
        $sqlIdUser = "SELECT id FROM kimai2_users WHERE alias = '$usuario'";
        $resultIdUser = $conn->query($sqlIdUser);
        $user = $resultIdUser->fetch_assoc();
        $user_id = $user['id'];

        // Revisar cada intervalo de tiempo posible para la cita dentro del horario de trabajo
        while (true) {
            // Asegurarse que sea un día de la semana
            while ($startTime->format('N') >= 6) {  // Saltar sábados y domingos
                $startTime = getNextBusinessDay($startTime);
                $startTime->setTime($businessHoursBegin->format('H'), $businessHoursBegin->format('i'), $businessHoursBegin->format('s'));  // Configurar al inicio del horario de trabajo
                $endTime = clone $startTime;
                $endTime->modify('+' . $segundos . ' seconds');
            }

            // Comprobar si ya existe una cita para este usuario y este intervalo de tiempo
            $start_time = $startTime->format('Y-m-d H:i:s');
            $end_time = $endTime->format('Y-m-d H:i:s');

            // Si la cita termina después del horario de trabajo, configurar al inicio del próximo día hábil
            $businessHoursEnd->setDate($endTime->format('Y'), $endTime->format('m'), $endTime->format('d'));
            if ($endTime > $businessHoursEnd) {
                $startTime = getNextBusinessDay($startTime);
                $startTime->setTime($businessHoursBegin->format('H'), $businessHoursBegin->format('i'), $businessHoursBegin->format('s'));  // Configurar al inicio del horario de trabajo
                $endTime = clone $startTime;
                $endTime->modify('+' . $segundos . ' seconds');
                continue;  // Volver al inicio del ciclo
            }

            $sql = "SELECT * FROM `kimai2_timesheet` WHERE `user` = $user_id AND ((`start_time` >= '$start_time' AND `start_time` < '$end_time') OR (`end_time` > '$start_time' AND `end_time` <= '$end_time'))";
            $result = $conn->query($sql);

            if ($result->num_rows > 0) {
                // Si ya existe una cita en este intervalo de tiempo, mover el inicio y fin de la cita al próximo intervalo posible
                $startTime->modify("+{$minutos} minutes");
                $endTime->modify("+{$minutos} minutes");
            } else {
                // Si no hay ninguna cita en este intervalo de tiempo, es un intervalo válido para la cita
                break;
            }
        }

        // Obtener el ID del último registro con cita_creada=1
        $sql = "SELECT MAX(id) AS id FROM kimai2_registro WHERE cita_creada = 1";
        $resultCita = $conn->query($sql);
        $rowCita= $resultCita->fetch_assoc();
        $lastId = $rowCita['id'];

        // Si no se encontró ningún registro con cita_creada=1, seleccionar el primer registro
        if ($lastId === null) {
            $sql = "SELECT * FROM kimai2_registro ORDER BY id LIMIT 1";
        } else {
            // Seleccionar los registros a partir del registro con ID que es uno mayor que el último ID con cita_creada=1
            $sql = "SELECT * FROM kimai2_registro WHERE id > $lastId ORDER BY id";
        }

        $resultRegistro = $conn->query($sql);
        $descripcion=$descripcion."\n CONVERSACION \n";
        // Procesar el resultado
        while ($rowRegistro = $resultRegistro->fetch_assoc()) {
            $descripcion=$descripcion. "Mensaje Recibido: {$rowRegistro['mensaje_recibido']}\n";
            $descripcion=$descripcion. "Mensaje Enviado: {$rowRegistro['mensaje_enviado']}\n";
            $descripcion=$descripcion. "-------------------------\n";
        }
        $descripcion = str_replace("'", "-", $descripcion);
        
        $sql = "INSERT INTO `kimai2_timesheet` 
            (`user`, `activity_id`, `project_id`, `start_time`, `end_time`, `duration`, `description`, `rate`, `hourly_rate`, `timezone`, `internal_rate`, `modified_at`, `date_tz`) VALUES 
            ('$user_id', '1', '$project_id', '$start_time', '$end_time', '$segundos', '" . $descripcion . "', '0', '0', 'Atlantic/Canary', '0', now(), now())";

        $conn->query($sql);
        
        return $start_time;
    } catch (Exception $e) {
        echo 'Excepción capturada: ',  $e->getMessage(), "\n";
        return null;
    }
}

function getNextBusinessDay($date)
{
    do {
        $date->modify('+1 day');
    } while ($date->format('N') >= 6);  // Saltar sábados y domingos
    return $date;
}

Los comentarios están cerrados.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad
Salir de la versión móvil