432 lines
No EOL
18 KiB
PHP
432 lines
No EOL
18 KiB
PHP
<?php
|
|
|
|
class RL_MailWarmer_Conversation_Handler {
|
|
|
|
/**
|
|
* Process conversations starting within the next 24 hours.
|
|
*
|
|
* This function finds conversations with a status of "new" that are scheduled to start within the next 24 hours,
|
|
* generates them, and updates their status to "generated." Limits to 50 conversations per run.
|
|
*/
|
|
public static function process_upcoming_conversations() {
|
|
log_to_file("process_upcoming_conversations - Running!");
|
|
global $wpdb;
|
|
$conversation_table = $wpdb->prefix . 'rl_mailwarmer_conversations';
|
|
// $current_time = current_time('mysql');
|
|
$current_time = date('Y-m-d H:i:s', strtotime('-24 hours'));
|
|
$future_time = date('Y-m-d H:i:s', strtotime('+24 hours'));
|
|
|
|
// Fetch up to 50 conversations starting within the next 24 hours
|
|
$conversations = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT * FROM $conversation_table WHERE status = %s AND first_message_timestamp BETWEEN %s AND %s LIMIT 1",
|
|
'new',
|
|
$current_time,
|
|
$future_time
|
|
),
|
|
ARRAY_A
|
|
);
|
|
// log_to_file("process_upcoming_conversations - Conversations: ", $conversations);
|
|
|
|
|
|
foreach ($conversations as $conversation) {
|
|
// log_to_file("process_upcoming_conversations - Conversation: ", $conversation);
|
|
try {
|
|
// Generate conversation content using AI
|
|
// $ai_response = self::fetch_conversation_from_ai($conversation);
|
|
$prompt = $conversation['prompt'];
|
|
|
|
// log_to_file("process_upcoming_conversations - AI prompt: ", $prompt);
|
|
|
|
// $ai_response = RL_MailWarmer_Campaign_Helper::clean_ai_response(RL_MailWarmer_Campaign_Helper::generate_ai_conversation($prompt));
|
|
// $ai_response = RL_MailWarmer_Campaign_Helper::generate_ai_conversation($prompt);
|
|
$ai_response = get_post_meta($conversation['campaign_id'], 'last_ai_response', true);
|
|
// log_to_file("process_upcoming_conversations - AI Response: ", $ai_response);
|
|
|
|
if (is_wp_error($ai_response)) {
|
|
return $ai_response; // Handle AI generation failure gracefully
|
|
}
|
|
|
|
$updated_conversation_steps = self::merge_timeline_with_ai_response($conversation['conversation_steps'], $ai_response);
|
|
// log_to_file("process_upcoming_conversations - Merged steps: ", $updated_conversation_steps);
|
|
// // Update conversation status to "generated"
|
|
$conversation_table = $wpdb->prefix . 'rl_mailwarmer_conversation';
|
|
$status = 'new';
|
|
$result = $wpdb->update(
|
|
$conversation_table,
|
|
// [],
|
|
['status' => $status, 'conversation_steps' => $updated_conversation_steps],
|
|
['id' => $conversation['id']],
|
|
['%s'],
|
|
['%s'],
|
|
['%d']
|
|
);
|
|
// log_to_file("process_upcoming_conversations - Update DB Result: ", $result);
|
|
|
|
$update_messages_db = self::update_messages_with_merged_output($conversation['id'], $updated_conversation_steps);
|
|
log_to_file("process_upcoming_conversations - Result of update_messages_with_merged_output(): ", $update_messages_db);
|
|
|
|
// Update the conversation with generated steps
|
|
// log_to_file("process_upcoming_conversations - Updating conversation_steps");
|
|
// if (RL_MailWarmer_Campaign_Helper::update_conversation_steps($conversation['id'], $updated_conversation_steps)) {
|
|
// // log_to_file("process_upcoming_conversations - Updated conversation_steps!");
|
|
// }
|
|
|
|
// Save the generated content to the conversation
|
|
// RL_MailWarmer_DB_Helper::update_conversation_steps($conversation['id'], $ai_response);
|
|
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Failed to generate conversation ID {$conversation['id']}: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
private static function update_messages_with_merged_output($conversation_id, $merged_output) {
|
|
log_to_file("update_messages_with_merged_output - merged_output: ", $merged_output);
|
|
global $wpdb;
|
|
$message_table = $wpdb->prefix . 'rl_mailwarmer_messages';
|
|
// $merged_output = json_decode($merged_output);
|
|
|
|
// Fetch all messages for the given conversation ID
|
|
$messages = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT * FROM $message_table WHERE conversation_id = %d ORDER BY `scheduled_for_timestamp` ASC",
|
|
$conversation_id
|
|
),
|
|
ARRAY_A
|
|
);
|
|
log_to_file("update_messages_with_merged_output - Found Messages: ", $messages);
|
|
|
|
if (empty($messages)) {
|
|
throw new Exception("No messages found for conversation ID $conversation_id.");
|
|
}
|
|
|
|
// Iterate through messages and merged output
|
|
foreach ($messages as $index => $message) {
|
|
if (!isset($merged_output[$index])) {
|
|
continue; // Skip if there's no corresponding merged output
|
|
}
|
|
|
|
$merged = $merged_output[$index];
|
|
// log_to_file("update_messages_with_merged_output - merged: $merged");
|
|
|
|
// Prepare updated data
|
|
// $updated_data = [
|
|
// 'status' => $merged['status'],
|
|
// 'scheduled_for_timestamp' => $merged['scheduled_for'],
|
|
// 'from_email' => $merged['from'],
|
|
// 'to_email' => json_encode($merged['to']),
|
|
// 'cc_email' => json_encode($merged['cc']),
|
|
// 'subject' => $merged['subject'],
|
|
// 'body' => $merged['body'],
|
|
// ];
|
|
// log_to_file("update_messages_with_merged_output - Updated Data: ", $updated_data);
|
|
|
|
// Update the database
|
|
// $wpdb->update(
|
|
// $message_table,
|
|
// $updated_data,
|
|
// ['id' => $message['id']], // Where clause
|
|
// [
|
|
// '%s', // status
|
|
// '%s', // scheduled_for_timestamp
|
|
// '%s', // from_email
|
|
// '%s', // to_email
|
|
// '%s', // cc_email
|
|
// '%s', // subject
|
|
// '%s', // body
|
|
// ],
|
|
// ['%d'] // ID
|
|
// );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Fetch a conversation from ChatGPT based on conversation parameters.
|
|
*
|
|
* @param array $conversation The conversation data.
|
|
* @return string The AI-generated conversation as JSON.
|
|
* @throws Exception If the API call fails.
|
|
*/
|
|
private static function fetch_conversation_from_ai($conversation) {
|
|
// Prepare the prompt for the AI request
|
|
$prompt = [
|
|
'profession' => $conversation['profession'],
|
|
'from' => $conversation['initiated_by'],
|
|
'to_pool' => json_decode($conversation['to_pool'], true),
|
|
'subject' => $conversation['subject'],
|
|
'num_of_replies' => $conversation['num_responses'],
|
|
'num_of_participants' => $conversation['num_participants'],
|
|
'max_days' => 3,
|
|
'can_reply' => json_decode($conversation['reply_pool'], true),
|
|
'available_to_cc' => json_decode($conversation['cc_pool'], true),
|
|
'start_date' => $conversation['first_message_timestamp'],
|
|
'end_date' => date('Y-m-d H:i:s', strtotime('+3 days', strtotime($conversation['first_message_timestamp'])))
|
|
];
|
|
|
|
// Call OpenAI API
|
|
$response = RL_MailWarmer_Api_Helper::call_openai_api($prompt);
|
|
|
|
if (!$response || !isset($response['choices'][0]['text'])) {
|
|
throw new Exception('Invalid response from OpenAI API');
|
|
}
|
|
|
|
return $response['choices'][0]['text'];
|
|
}
|
|
|
|
public static function merge_timeline_with_ai_response($conversation_json, $ai_response_json) {
|
|
// Decode the JSON inputs into arrays
|
|
$conversation = json_decode($conversation_json, true);
|
|
$ai_response = json_decode($ai_response_json, true);
|
|
|
|
// Ensure both arrays have the same number of elements
|
|
$merged = [];
|
|
$count_timeline = count($conversation);
|
|
$count_ai_response = count($ai_response);
|
|
|
|
if ($count_ai_response > $count_timeline) {
|
|
// Trim the AI responses to match the timeline count
|
|
$ai_response = array_slice($ai_response, 0, $count_timeline);
|
|
} elseif ($count_ai_response < $count_timeline) {
|
|
throw new Exception('The number of AI responses is less than the timeline steps.');
|
|
}
|
|
|
|
// Merge corresponding elements
|
|
foreach ($conversation as $index => $timeline_step) {
|
|
$ai_message = $ai_response[$index];
|
|
$merged[] = array_merge($timeline_step, $ai_message);
|
|
}
|
|
|
|
// Return the merged result as JSON
|
|
return json_encode($merged, JSON_PRETTY_PRINT);
|
|
}
|
|
}
|
|
|
|
|
|
add_action('admin_menu', function () {
|
|
add_menu_page(
|
|
__('Conversations', 'rl-mailwarmer'), // Page title
|
|
__('Conversations', 'rl-mailwarmer'), // Menu title
|
|
'manage_options', // Capability
|
|
'rl-mailwarmer-conversations', // Menu slug
|
|
'rl_mailwarmer_render_conversations_page', // Callback function
|
|
'dashicons-email', // Icon
|
|
8 // Position
|
|
);
|
|
});
|
|
|
|
/**
|
|
* Render the Conversations admin page with checkboxes and a Delete button.
|
|
*/
|
|
function rl_mailwarmer_render_conversations_page() {
|
|
if (!current_user_can('manage_options')) {
|
|
return;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
$table_name = $wpdb->prefix . 'rl_mailwarmer_conversations'; // Conversation table
|
|
$conversations = $wpdb->get_results("SELECT * FROM $table_name ORDER BY created_at DESC");
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h1><?php esc_html_e('Conversations', 'rl-mailwarmer'); ?></h1>
|
|
|
|
<?php if (empty($conversations)) : ?>
|
|
<p><?php esc_html_e('No conversations found.', 'rl-mailwarmer'); ?></p>
|
|
<?php else : ?>
|
|
<form id="conversation-management-form" method="post">
|
|
<table class="widefat fixed striped">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 50px;">
|
|
<input type="checkbox" id="check-all-conversations">
|
|
</th>
|
|
<th><?php esc_html_e('ID', 'rl-mailwarmer'); ?></th>
|
|
<th><?php esc_html_e('Campaign ID', 'rl-mailwarmer'); ?></th>
|
|
<th><?php esc_html_e('Created At', 'rl-mailwarmer'); ?></th>
|
|
<th><?php esc_html_e('Steps', 'rl-mailwarmer'); ?></th>
|
|
<th><?php esc_html_e('Prompt', 'rl-mailwarmer'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($conversations as $conversation) : ?>
|
|
<tr>
|
|
<td>
|
|
<input type="checkbox" name="selected_conversations[]" value="<?php echo esc_attr($conversation->id); ?>">
|
|
</td>
|
|
<td><?php echo esc_html($conversation->id); ?></td>
|
|
<td><?php echo esc_html($conversation->campaign_id); ?></td>
|
|
<td><?php echo esc_html($conversation->created_at); ?></td>
|
|
<td><?php echo esc_html($conversation->conversation_steps); ?></td>
|
|
<td>
|
|
<details>
|
|
<summary><?php esc_html_e('View Prompt', 'rl-mailwarmer'); ?></summary>
|
|
<pre><?php echo esc_html($conversation->prompt); ?></pre>
|
|
</details>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<p>
|
|
<button type="button" id="delete-selected-conversations" class="button button-primary">
|
|
<?php esc_html_e('Delete Items', 'rl-mailwarmer'); ?>
|
|
</button>
|
|
</p>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
// Select all conversations
|
|
const checkAll = document.getElementById('check-all-conversations');
|
|
const checkboxes = document.querySelectorAll('input[name="selected_conversations[]"]');
|
|
|
|
checkAll.addEventListener('change', function () {
|
|
checkboxes.forEach(checkbox => checkbox.checked = checkAll.checked);
|
|
});
|
|
|
|
// Handle delete button click
|
|
document.getElementById('delete-selected-conversations').addEventListener('click', function () {
|
|
const selectedIds = Array.from(checkboxes)
|
|
.filter(checkbox => checkbox.checked)
|
|
.map(checkbox => checkbox.value);
|
|
|
|
if (selectedIds.length === 0) {
|
|
alert('<?php esc_html_e('Please select at least one conversation to delete.', 'rl-mailwarmer'); ?>');
|
|
return;
|
|
}
|
|
|
|
if (confirm('<?php esc_html_e('Are you sure you want to delete the selected conversations?', 'rl-mailwarmer'); ?>')) {
|
|
jQuery.post(ajaxurl, {
|
|
action: 'rl_delete_conversations',
|
|
conversation_ids: selectedIds,
|
|
}, function (response) {
|
|
if (response.success) {
|
|
alert('<?php esc_html_e('Selected conversations deleted successfully.', 'rl-mailwarmer'); ?>');
|
|
location.reload(); // Reload the page to update the list
|
|
} else {
|
|
alert('<?php esc_html_e('Failed to delete conversations.', 'rl-mailwarmer'); ?>');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<?php
|
|
}
|
|
|
|
|
|
function rl_mailwarmer_get_conversations($page, $per_page = 20) {
|
|
global $wpdb;
|
|
|
|
$offset = ($page - 1) * $per_page;
|
|
|
|
$total = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}rl_mailwarmer_conversation");
|
|
$conversations = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT * FROM {$wpdb->prefix}rl_mailwarmer_conversation ORDER BY created_at DESC LIMIT %d OFFSET %d",
|
|
$per_page,
|
|
$offset
|
|
));
|
|
|
|
return ['conversations' => $conversations, 'total' => $total];
|
|
}
|
|
|
|
add_action('wp_ajax_rl_delete_conversations', function () {
|
|
global $wpdb;
|
|
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error(['message' => __('Permission denied.', 'rl-mailwarmer')]);
|
|
}
|
|
|
|
$conversation_ids = isset($_POST['conversation_ids']) ? array_map('intval', $_POST['conversation_ids']) : [];
|
|
|
|
if (empty($conversation_ids)) {
|
|
wp_send_json_error(['message' => __('No conversations selected.', 'rl-mailwarmer')]);
|
|
}
|
|
|
|
$table_name = $wpdb->prefix . 'rl_mailwarmer_conversation';
|
|
|
|
// Delete selected conversations
|
|
$placeholders = implode(',', array_fill(0, count($conversation_ids), '%d'));
|
|
$query = "DELETE FROM $table_name WHERE id IN ($placeholders)";
|
|
$result = $wpdb->query($wpdb->prepare($query, $conversation_ids));
|
|
|
|
if ($result === false) {
|
|
wp_send_json_error(['message' => __('Failed to delete conversations.', 'rl-mailwarmer')]);
|
|
}
|
|
|
|
wp_send_json_success(['message' => __('Conversations deleted successfully.', 'rl-mailwarmer')]);
|
|
});
|
|
|
|
|
|
// Add the metabox
|
|
add_action('add_meta_boxes', 'rl_mailwarmer_add_process_conversations_metabox');
|
|
function rl_mailwarmer_add_process_conversations_metabox() {
|
|
add_meta_box(
|
|
'rl-process-conversations',
|
|
__('Process Upcoming Conversations', 'rl-mailwarmer'),
|
|
'rl_mailwarmer_process_conversations_metabox_callback',
|
|
'campaign',
|
|
'side',
|
|
'default'
|
|
);
|
|
}
|
|
|
|
// Metabox callback function
|
|
function rl_mailwarmer_process_conversations_metabox_callback($post) {
|
|
// Nonce field for security
|
|
wp_nonce_field('rl_process_conversations_nonce', 'rl_process_conversations_nonce_field');
|
|
|
|
?>
|
|
<button type="button" id="rl_process_conversations_button" class="button button-primary">
|
|
<?php _e('Process Upcoming Conversations', 'rl-mailwarmer'); ?>
|
|
</button>
|
|
<div id="rl_process_conversations_result" style="margin-top: 10px;"></div>
|
|
<?php
|
|
}
|
|
|
|
// Enqueue JavaScript
|
|
add_action('admin_enqueue_scripts', 'rl_mailwarmer_enqueue_process_conversations_script');
|
|
function rl_mailwarmer_enqueue_process_conversations_script($hook) {
|
|
if ($hook === 'post.php' || $hook === 'post-new.php') {
|
|
wp_enqueue_script(
|
|
'rl-process-conversations',
|
|
RL_MAILWARMER_URL . 'js/rl-process-conversations.js',
|
|
['jquery'],
|
|
'1.0',
|
|
true
|
|
);
|
|
|
|
wp_localize_script('rl-process-conversations', 'rlProcessConversations', [
|
|
'ajax_url' => admin_url('admin-ajax.php'),
|
|
'nonce' => wp_create_nonce('rl_process_conversations_nonce'),
|
|
]);
|
|
}
|
|
}
|
|
|
|
// AJAX handler
|
|
add_action('wp_ajax_rl_process_upcoming_conversations', 'rl_mailwarmer_process_upcoming_conversations_handler');
|
|
function rl_mailwarmer_process_upcoming_conversations_handler() {
|
|
check_ajax_referer('rl_process_conversations_nonce', 'security');
|
|
|
|
$post_id = intval($_POST['post_id']);
|
|
|
|
if (!$post_id) {
|
|
wp_send_json_error(__('Invalid campaign ID.', 'rl-mailwarmer'));
|
|
}
|
|
|
|
try {
|
|
// Call the function to process upcoming conversations
|
|
RL_MailWarmer_Conversation_Handler::process_upcoming_conversations($post_id);
|
|
|
|
wp_send_json_success(__('Conversations processed successfully.', 'rl-mailwarmer'));
|
|
} catch (Exception $e) {
|
|
wp_send_json_error(__('Error processing conversations: ', 'rl-mailwarmer') . $e->getMessage());
|
|
}
|
|
}
|