# SYNDIA_SURVEY RESPONSE ISSUE - REPOSITORY
================================================================================
Project Name: SYNDIA_Survey response issue
Created: 2025-09-25 06:53:20
Last Updated: 2025-09-25 06:53:28
Source ZIP: syndia.kreahealthcare.com.zip
Total Files: 93
Total Folders: 7
================================================================================
## FILE STRUCTURE
================================================================================
SYNDIA_Survey response issue/
└── syndia.kreahealthcare.com/
├── .well-known/
│ └── acme-challenge/
│ └── dTZpZTVtazRsbGVqaHRqbDFjM3FrdTMycDA
├── ajax_process_combinations.php
├── analysis_control.php
├── assets/
│ ├── css
│ └── js/
│ ├── integrity-check-script.js
│ ├── panel_alignment.js
│ └── panel_directives.js
├── base.php
├── calculate_available_samples.php
├── calculate_panel_alignment.php
├── cgi-bin
├── check_generation_progress.php
├── check_progress.php
├── connect_survey.php
├── conservative_optimization_processor.php
├── create_selection.php
├── dashboard.php
├── db.php
├── delete_directive.php
├── delete_selection.php
├── delete_survey.php
├── delete_survey_question.php
├── diagnostic_optimaize.php
├── direct_gpt_test.php
├── disconnect_survey.php
├── emergency_check.php
├── enhanced_get_optimization_progress.php
├── enhanced_process_optimization.php
├── error_log
├── export_attributes.php
├── export_panel.php
├── export_project_data.php
├── export_raw_data.php
├── export_selection.php
├── export_statistics.php
├── export_statistics_check.php
├── file_check.php
├── fix_optimaize.php
├── fix_stuck_analysis.php
├── generate_optimized_panel.php
├── generate_responses.php
├── generate_responses_worker.php
├── get_attribute_choices.php
├── get_available_count.php
├── get_available_surveys.php
├── get_connected_surveys.php
├── get_impossible_combinations.php
├── get_optimization_progress.php
├── get_panelist_details.php
├── get_recent_combinations.php
├── get_selection_form.php
├── get_surveys.php
├── get_survey_questions.php
├── impossible_combinations_api.php
├── includes/
│ ├── auth.php
│ ├── config.php
│ ├── db.php
│ ├── functions.php
│ ├── GptHelper.php
│ ├── IntegrityCheckHandler.php
│ ├── IntegrityCheckHandlerBackup.php
│ └── survey_functions.php
├── index.php
├── init_admin.php
├── integrity_check_handler.php
├── kill_processes.php
├── login.php
├── logout.php
├── manage_project.php
├── move_survey_question.php
├── openai_diagnostic.php
├── optimaize.php
├── optimization_analysis.log
├── panel.php
├── panel_action_handler.php
├── panel_alignment.php
├── panel_alignment_handler.php
├── process_optimization_analysis.php
├── projects.php
├── QueueManager.php
├── queue_processor.php
├── quick_start_optimaize.php
├── save_survey.php
├── save_survey_question.php
├── simple_foreground_processor.php
├── start_optimization_analysis.php
├── status_check.php
├── surveys.php
├── survey_form.php
├── survey_preview.php
├── update_directive_status.php
├── update_optimaize_db.php
├── update_question_order.php
├── users.php
└── view_selection.php
================================================================================
## FILE CONTENTS
================================================================================
### FILE 1: syndia.kreahealthcare.com/ajax_process_combinations.php
- Type: PHP
- Size: 6.6 KB
- Path: syndia.kreahealthcare.com
- Name: ajax_process_combinations.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$db = Database::getInstance();
// Get batch size from request (default 3 for shared hosting)
$batchSize = isset($_POST['batch_size']) ? min(10, max(1, (int)$_POST['batch_size'])) : 3;
// Check if analysis should be running
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state WHERE is_running = 1 ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
if (!$state) {
echo json_encode([
'success' => false,
'message' => 'No active analysis found',
'should_stop' => true
]);
exit;
}
// Check if we should pause
if ($state['should_pause']) {
echo json_encode([
'success' => true,
'message' => 'Analysis paused',
'processed' => 0,
'should_stop' => true
]);
exit;
}
// Get next batch of unprocessed combinations
$query = $db->query("
SELECT id, attribute1_name, choice1, attribute2_name, choice2
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT $batchSize
");
if (!$query || $query->num_rows == 0) {
// No more combinations to process - mark as complete
$db->query("UPDATE optimization_analysis_state SET
is_running = 0,
completed_at = NOW()
WHERE is_running = 1");
echo json_encode([
'success' => true,
'message' => 'Analysis completed!',
'processed' => 0,
'completed' => true,
'should_stop' => true
]);
exit;
}
$combinations = [];
while ($row = $query->fetch_assoc()) {
$combinations[] = $row;
}
$processed = 0;
$errors = 0;
$results = [];
// Process each combination
foreach ($combinations as $combo) {
try {
$result = processSingleCombination($combo, $db);
if ($result['success']) {
$processed++;
$results[] = [
'id' => $combo['id'],
'status' => $result['is_impossible'] ? 'impossible' : 'possible',
'reasoning' => substr($result['reasoning'], 0, 100)
];
} else {
$errors++;
$results[] = [
'id' => $combo['id'],
'status' => 'error',
'reasoning' => $result['error']
];
}
} catch (Exception $e) {
$errors++;
$results[] = [
'id' => $combo['id'],
'status' => 'error',
'reasoning' => $e->getMessage()
];
}
}
// Update progress
$totalProcessedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$totalProcessed = $totalProcessedQuery ? $totalProcessedQuery->fetch_assoc()['count'] : 0;
$db->query("UPDATE optimization_analysis_state SET
processed_combinations = $totalProcessed,
last_updated = NOW()
WHERE is_running = 1");
echo json_encode([
'success' => true,
'processed' => $processed,
'errors' => $errors,
'total_processed' => $totalProcessed,
'results' => $results,
'has_more' => true,
'message' => "Processed batch: $processed success, $errors errors"
]);
} catch (Exception $e) {
error_log("AJAX processor error: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => $e->getMessage(),
'should_stop' => true
]);
}
function processSingleCombination($combination, $db) {
try {
// Build the prompt
$prompt = sprintf(
"Analyze this Indian demographic combination:\n\n%s = %s\n%s = %s\n\nIs this combination realistic in Indian society? Consider cultural norms, economic factors, and social structures. Respond with 'POSSIBLE' or 'IMPOSSIBLE' followed by a brief reason (max 50 words).",
$combination['attribute1_name'],
$combination['choice1'],
$combination['attribute2_name'],
$combination['choice2']
);
$messages = [
[
'role' => 'system',
'content' => 'You are an expert in Indian demographics and social structures. Analyze combinations for realism.'
],
[
'role' => 'user',
'content' => $prompt
]
];
// Make GPT request with rate limiting
$response = GptHelper::makeRequest($messages, 'gpt-4o-mini', 0.1);
if (!$response['success']) {
throw new Exception("GPT API error: " . $response['error']);
}
$content = trim($response['response']);
$isImpossible = stripos($content, 'IMPOSSIBLE') === 0 ? 1 : 0;
// Extract reasoning
$reasoning = trim(str_ireplace(['POSSIBLE', 'IMPOSSIBLE'], '', $content));
if (empty($reasoning)) {
$reasoning = $content;
}
// Update database
$stmt = $db->prepare("UPDATE panel_directives SET
llm_checked = 1,
is_impossible = ?,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?");
$stmt->bind_param('isi', $isImpossible, $reasoning, $combination['id']);
if (!$stmt->execute()) {
throw new Exception("Database update failed: " . $db->getLastError());
}
return [
'success' => true,
'is_impossible' => $isImpossible,
'reasoning' => $reasoning
];
} catch (Exception $e) {
// Mark as checked with error
$stmt = $db->prepare("UPDATE panel_directives SET
llm_checked = 1,
is_impossible = 0,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?");
$errorMsg = "Error: " . $e->getMessage();
$stmt->bind_param('si', $errorMsg, $combination['id']);
$stmt->execute();
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 2: syndia.kreahealthcare.com/analysis_control.php
- Type: PHP
- Size: 11.36 KB
- Path: syndia.kreahealthcare.com
- Name: analysis_control.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$input = json_decode(file_get_contents('php://input'), true);
$action = $input['action'] ?? '';
if (!in_array($action, ['start', 'pause', 'stop', 'reset', 'generate', 'status'])) {
throw new Exception('Invalid action');
}
$db = Database::getInstance();
switch ($action) {
case 'start':
$result = startAnalysis($db);
break;
case 'pause':
$result = pauseAnalysis($db);
break;
case 'stop':
$result = stopAnalysis($db);
break;
case 'reset':
$result = resetAnalysisState($db);
break;
case 'generate':
$result = generateCombinationsAction($db);
break;
case 'status':
$result = getAnalysisStatus($db);
break;
}
echo json_encode($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
function startAnalysis($db) {
try {
// Check if analysis is already running
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state WHERE is_running = 1 LIMIT 1");
if ($stateQuery && $stateQuery->num_rows > 0) {
return [
'success' => false,
'message' => 'Analysis is already running'
];
}
// Check for new attributes and regenerate combinations if needed
$newCombinationsGenerated = regenerateCombinationsIfNeeded($db);
// Get total combinations count
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalQuery->fetch_assoc()['count'];
if ($totalCombinations == 0) {
// Generate combinations if none exist
generateCombinations($db);
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalQuery->fetch_assoc()['count'];
}
// Get processed count
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$processedCount = $processedQuery->fetch_assoc()['count'];
// Update or create analysis state
$existingState = $db->query("SELECT id FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
if ($existingState && $existingState->num_rows > 0) {
$stateId = $existingState->fetch_assoc()['id'];
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 1,
started_at = NOW(),
total_combinations = ?,
processed_combinations = ?,
should_pause = 0,
completed_at = NULL
WHERE id = ?");
$stmt->bind_param('iii', $totalCombinations, $processedCount, $stateId);
} else {
$stmt = $db->prepare("INSERT INTO optimization_analysis_state
(total_combinations, processed_combinations, is_running, started_at, should_pause)
VALUES (?, ?, 1, NOW(), 0)");
$stmt->bind_param('ii', $totalCombinations, $processedCount);
}
if (!$stmt->execute()) {
throw new Exception("Failed to update analysis state");
}
// Start background process with proper file path
$processFile = file_exists('enhanced_process_optimization.php') ?
'enhanced_process_optimization.php' :
'process_optimization_analysis.php';
$command = "php " . __DIR__ . "/$processFile > /dev/null 2>&1 &";
exec($command);
return [
'success' => true,
'message' => 'Analysis started successfully',
'total_combinations' => $totalCombinations,
'new_combinations_generated' => $newCombinationsGenerated,
'process_file_used' => $processFile
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error starting analysis: ' . $e->getMessage()
];
}
}
function pauseAnalysis($db) {
try {
// Set pause flag - the background process will check this
$stmt = $db->prepare("UPDATE optimization_analysis_state SET should_pause = 1 WHERE is_running = 1");
if (!$stmt->execute()) {
throw new Exception("Failed to pause analysis");
}
// Wait a moment for the process to pause
sleep(2);
// Update state to paused
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 0,
should_pause = 0
WHERE should_pause = 1");
$stmt->execute();
return [
'success' => true,
'message' => 'Analysis paused successfully'
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error pausing analysis: ' . $e->getMessage()
];
}
}
function stopAnalysis($db) {
try {
// Stop analysis and reset state
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 0,
should_pause = 0,
completed_at = NOW()
WHERE is_running = 1");
if (!$stmt->execute()) {
throw new Exception("Failed to stop analysis");
}
return [
'success' => true,
'message' => 'Analysis stopped successfully'
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error stopping analysis: ' . $e->getMessage()
];
}
}
function regenerateCombinationsIfNeeded($db) {
try {
// Get the latest modification time of attributes
$attrQuery = $db->query("SELECT MAX(updated_at) as latest FROM attributes");
$latestAttr = $attrQuery->fetch_assoc()['latest'];
// Get the creation time of the most recent directive
$directiveQuery = $db->query("SELECT MAX(created_at) as latest FROM panel_directives");
$latestDirective = $directiveQuery->fetch_assoc()['latest'];
// If attributes were modified after the last directive creation, regenerate
if ($latestAttr && $latestDirective && strtotime($latestAttr) > strtotime($latestDirective)) {
error_log("Regenerating combinations due to attribute changes");
// Clear existing unchecked directives
$db->query("DELETE FROM panel_directives WHERE llm_checked = 0");
// Generate new combinations
generateCombinations($db);
return true;
}
return false;
} catch (Exception $e) {
error_log("Error checking for new combinations: " . $e->getMessage());
return false;
}
}
function generateCombinations($db) {
try {
// Get all attributes
$attributesQuery = $db->query("SELECT id, name, choices FROM attributes ORDER BY id");
$attributes = [];
while ($attr = $attributesQuery->fetch_assoc()) {
$choices = json_decode($attr['choices'], true);
if ($choices && is_array($choices)) {
$attributes[] = [
'id' => $attr['id'],
'name' => $attr['name'],
'choices' => $choices
];
}
}
if (count($attributes) < 2) {
throw new Exception("Need at least 2 attributes to generate combinations");
}
$generatedCount = 0;
$stmt = $db->prepare("INSERT IGNORE INTO panel_directives
(attribute1_id, attribute2_id, choice1, choice2, attribute1_name, attribute2_name, status)
VALUES (?, ?, ?, ?, ?, ?, 'pending')");
// Generate all possible combinations between different attributes
for ($i = 0; $i < count($attributes); $i++) {
for ($j = $i + 1; $j < count($attributes); $j++) {
$attr1 = $attributes[$i];
$attr2 = $attributes[$j];
foreach ($attr1['choices'] as $choice1) {
foreach ($attr2['choices'] as $choice2) {
$stmt->bind_param('iissss',
$attr1['id'], $attr2['id'],
$choice1, $choice2,
$attr1['name'], $attr2['name']
);
if ($stmt->execute()) {
$generatedCount++;
}
}
}
}
}
error_log("Generated $generatedCount new combinations");
return $generatedCount;
} catch (Exception $e) {
error_log("Error generating combinations: " . $e->getMessage());
throw $e;
}
}
function resetAnalysisState($db) {
try {
// Stop any running analysis
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 0,
should_pause = 0,
completed_at = NOW()
WHERE is_running = 1");
if (!$stmt->execute()) {
throw new Exception("Failed to reset analysis state");
}
return [
'success' => true,
'message' => 'Analysis state reset successfully'
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error resetting analysis state: ' . $e->getMessage()
];
}
}
function generateCombinationsAction($db) {
try {
$count = generateCombinations($db);
return [
'success' => true,
'message' => "Generated $count combinations successfully"
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error generating combinations: ' . $e->getMessage()
];
}
}
function getAnalysisStatus($db) {
try {
// Get current state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
// Get statistics
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$total = $totalQuery->fetch_assoc()['count'];
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$processed = $processedQuery->fetch_assoc()['count'];
return [
'success' => true,
'state' => $state,
'statistics' => [
'total' => $total,
'processed' => $processed,
'pending' => $total - $processed
]
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Error getting analysis status: ' . $e->getMessage()
];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 3: syndia.kreahealthcare.com/base.php
- Type: PHP
- Size: 70.98 KB
- Path: syndia.kreahealthcare.com
- Name: base.php
------------------------------------------------------------
isAdmin()) {
redirectTo('dashboard.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
$error = '';
$success = '';
// Handle CSV Export
if (isset($_GET['action']) && $_GET['action'] === 'export') {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="statistics_export_' . date('Y-m-d') . '.csv"');
$output = fopen('php://output', 'w');
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF)); // Add BOM for UTF-8
// Write headers
fputcsv($output, ['Statistic Name', 'Type', 'Attributes', 'Sum Type', 'Combination', 'Percentage', 'Created Date']);
// Get all statistics with their combinations
$stats = $db->query("
SELECT s.*,
GROUP_CONCAT(DISTINCT a.name) as attribute_names,
DATE_FORMAT(s.created_at, '%b %d, %Y') as created_date
FROM statistics s
LEFT JOIN statistic_attributes sa ON s.id = sa.statistic_id
LEFT JOIN attributes a ON a.id = sa.attribute_id
GROUP BY s.id
");
while ($stat = $stats->fetch_assoc()) {
$combinations = $db->query("
SELECT combination_values, percentage
FROM statistic_combinations
WHERE statistic_id = " . $stat['id']);
while ($combo = $combinations->fetch_assoc()) {
$values = json_decode($combo['combination_values'], true);
fputcsv($output, [
$stat['name'],
$stat['type'],
$stat['attribute_names'],
$stat['sum_type'],
str_replace('×', 'x', implode(' x ', $values)),
$combo['percentage'],
$stat['created_date']
]);
}
}
fclose($output);
exit;
}
// AJAX handler for fetching combinations
if (isset($_GET['action']) && $_GET['action'] === 'getCombinations') {
$statisticId = (int)$_GET['id'];
// Enhanced query to get all necessary statistic details including selected attributes
$statQuery = $db->query("
SELECT s.*,
GROUP_CONCAT(DISTINCT a.id ORDER BY a.id) as attribute_ids,
GROUP_CONCAT(DISTINCT a.name ORDER BY a.id) as attribute_names,
GROUP_CONCAT(DISTINCT a.choice_type ORDER BY a.id) as attribute_types,
s.type as statistic_type
FROM statistics s
JOIN statistic_attributes sa ON s.id = sa.statistic_id
JOIN attributes a ON a.id = sa.attribute_id
WHERE s.id = $statisticId
GROUP BY s.id
");
$statistic = $statQuery->fetch_assoc();
$combinations = $db->query("
SELECT sc.combination_values, sc.percentage
FROM statistic_combinations sc
WHERE sc.statistic_id = $statisticId
ORDER BY sc.id
");
$result = [
'statistic' => $statistic,
'combinations' => []
];
if ($combinations) {
while ($combo = $combinations->fetch_assoc()) {
$values = json_decode($combo['combination_values'], true);
$result['combinations'][] = [
'values' => $values,
'combination' => implode(' × ', $values),
'percentage' => number_format($combo['percentage'], 4)
];
}
}
header('Content-Type: application/json');
echo json_encode($result);
exit;
}
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$redirectSection = '';
switch ($action) {
case 'create_attribute':
$name = sanitizeInput($_POST['attribute_name']);
$type = sanitizeInput($_POST['choice_type']);
$choices = sanitizeInput($_POST['choices']);
$choicesArray = array_filter(array_map('trim', explode("\n", $choices)));
$choicesJson = json_encode($choicesArray);
$sql = "INSERT INTO attributes (name, choice_type, choices, created_by)
VALUES ('" . $db->escape($name) . "',
'" . $db->escape($type) . "',
'" . $db->escape($choicesJson) . "',
" . (int)$_SESSION['user_id'] . ")";
if ($db->query($sql)) {
$success = "Attribute created successfully";
$redirectSection = 'attributes';
} else {
$error = "Failed to create attribute";
}
break;
case 'update_attribute':
$attributeId = (int)$_POST['attribute_id'];
$name = sanitizeInput($_POST['attribute_name']);
$type = sanitizeInput($_POST['choice_type']);
$choices = sanitizeInput($_POST['choices']);
$choicesArray = array_filter(array_map('trim', explode("\n", $choices)));
$choicesJson = json_encode($choicesArray);
$sql = "UPDATE attributes SET
name = '" . $db->escape($name) . "',
choice_type = '" . $db->escape($type) . "',
choices = '" . $db->escape($choicesJson) . "'
WHERE id = $attributeId";
if ($db->query($sql)) {
$success = "Attribute updated successfully";
$redirectSection = 'attributes';
} else {
$error = "Failed to update attribute";
}
break;
case 'delete_attribute':
$attributeId = (int)$_POST['attribute_id'];
if ($db->query("DELETE FROM attributes WHERE id = $attributeId")) {
$success = "Attribute deleted successfully";
$redirectSection = 'attributes';
} else {
$error = "Failed to delete attribute";
}
break;
case 'create_statistics':
$type = sanitizeInput($_POST['statistics_type']);
$attributes = [];
$name = '';
$sumType = '100';
if ($type === 'single') {
$attributeId = (int)$_POST['single_attribute'];
$attributes[] = $attributeId;
$attrQuery = $db->query("SELECT name, choice_type FROM attributes WHERE id = $attributeId");
$attr = $attrQuery->fetch_assoc();
$name = $attr['name'];
$sumType = $attr['choice_type'] === 'multiple' ? 'any' : '100';
} else {
$attributes = array_map('intval', $_POST['combined_attributes']);
if (count($attributes) < 2) {
$error = "Please select at least 2 attributes for combined statistics";
break;
}
$attrNames = [];
$hasMultiple = false;
foreach ($attributes as $attrId) {
$attrQuery = $db->query("SELECT name, choice_type FROM attributes WHERE id = $attrId");
$attr = $attrQuery->fetch_assoc();
$attrNames[] = $attr['name'];
if ($attr['choice_type'] === 'multiple') {
$hasMultiple = true;
}
}
sort($attrNames);
$name = implode(" × ", $attrNames);
$sumType = $hasMultiple ? 'any' : '100';
}
$db->query("START TRANSACTION");
try {
$sql = "INSERT INTO statistics (name, type, sum_type, created_by)
VALUES ('" . $db->escape($name) . "',
'" . $db->escape($type) . "',
'$sumType',
" . (int)$_SESSION['user_id'] . ")";
if (!$db->query($sql)) {
throw new Exception("Failed to create statistics");
}
$statisticId = $db->getLastInsertId();
foreach ($attributes as $attrId) {
$sql = "INSERT INTO statistic_attributes (statistic_id, attribute_id)
VALUES ($statisticId, $attrId)";
if (!$db->query($sql)) {
throw new Exception("Failed to link attributes");
}
}
$combinations = json_decode($_POST['combinations'], true);
foreach ($combinations as $combination) {
$sql = "INSERT INTO statistic_combinations (statistic_id, combination_values, percentage)
VALUES ($statisticId,
'" . $db->escape(json_encode($combination['values'])) . "',
" . (float)$combination['percentage'] . ")";
if (!$db->query($sql)) {
throw new Exception("Failed to insert combinations");
}
}
$db->query("COMMIT");
$success = "Statistics created successfully";
$redirectSection = 'statistics';
} catch (Exception $e) {
$db->query("ROLLBACK");
$error = $e->getMessage();
}
break;
case 'update_statistics':
$statisticId = (int)$_POST['statistic_id'];
$combinations = json_decode($_POST['combinations'], true);
$db->query("START TRANSACTION");
try {
$db->query("DELETE FROM statistic_combinations WHERE statistic_id = $statisticId");
foreach ($combinations as $combination) {
$sql = "INSERT INTO statistic_combinations (statistic_id, combination_values, percentage)
VALUES ($statisticId,
'" . $db->escape(json_encode($combination['values'])) . "',
" . (float)$combination['percentage'] . ")";
if (!$db->query($sql)) {
throw new Exception("Failed to update combinations");
}
}
$db->query("COMMIT");
$success = "Statistics updated successfully";
$redirectSection = 'statistics';
} catch (Exception $e) {
$db->query("ROLLBACK");
$error = $e->getMessage();
}
break;
case 'delete_statistics':
$statisticId = (int)$_POST['statistic_id'];
if ($db->query("DELETE FROM statistics WHERE id = $statisticId")) {
$success = "Statistics deleted successfully";
$redirectSection = 'statistics';
} else {
$error = "Failed to delete statistics";
}
break;
}
// Redirect with section parameter if specified
if ($redirectSection && !$error) {
redirectTo("base.php?section=" . $redirectSection);
}
}
// Get all attributes
$attributes = $db->query("SELECT *, DATE_FORMAT(created_at, '%b %d, %Y') as created_date FROM attributes ORDER BY created_at DESC");
// Get statistics with counts and attribute details
$statistics = $db->query("
SELECT s.*,
COUNT(DISTINCT sa.attribute_id) as attribute_count,
COUNT(DISTINCT sc.id) as combination_count,
GROUP_CONCAT(DISTINCT a.name) as attribute_names,
DATE_FORMAT(s.created_at, '%b %d, %Y') as created_date
FROM statistics s
LEFT JOIN statistic_attributes sa ON s.id = sa.statistic_id
LEFT JOIN statistic_combinations sc ON s.id = sc.statistic_id
LEFT JOIN attributes a ON a.id = sa.attribute_id
GROUP BY s.id
ORDER BY s.created_at DESC
");
// Get all combinations for statistics check with deviation
// Replace the current query for $allCombinations with this:
$allCombinations = $db->query("
SELECT
s.name as statistic_name,
sc.combination_values,
sc.percentage as target_percentage,
sc.actual_percentage as panel_percentage
FROM statistics s
JOIN statistic_combinations sc ON s.id = sc.statistic_id
ORDER BY s.name, sc.id
");
// For debugging
if (!$allCombinations) {
error_log("Query Error: " . $db->getLastError());
}
// Determine active section
$activeSection = isset($_GET['section']) ? $_GET['section'] : 'attributes';
if (!in_array($activeSection, ['attributes', 'statistics', 'statisticCheck'])) {
$activeSection = 'attributes';
}
// Get attribute counts
$totalAttributes = $attributes->num_rows;
$singleChoiceCount = $db->query("SELECT COUNT(*) as count FROM attributes WHERE choice_type = 'single'")->fetch_assoc()['count'];
$multipleChoiceCount = $db->query("SELECT COUNT(*) as count FROM attributes WHERE choice_type = 'multiple'")->fetch_assoc()['count'];
// Get statistics counts
$totalStats = $statistics->num_rows;
$singleStats = $db->query("SELECT COUNT(DISTINCT s.id) as count FROM statistics s WHERE s.type = 'single'")->fetch_assoc()['count'];
$combinedStats = $db->query("SELECT COUNT(DISTINCT s.id) as count FROM statistics s WHERE s.type = 'combined'")->fetch_assoc()['count'];
?>
Base |
Attributes
Statistics
Statistic Check
Attribute Name
Choice Type
Choices
Created
Actions
num_rows > 0): ?>
fetch_assoc()): ?>
Choice
Edit
Delete
No attributes found
Name
Type
Attributes
Combinations
Sum
Created
Actions
num_rows > 0): ?>
fetch_assoc()): ?>
Edit
Delete
No statistics found
query("
SELECT COUNT(*) as count
FROM statistic_combinations
")->fetch_assoc()['count'];
// Just show the total count without trying to calculate deviations
?>
Combination Name
Combination
Target %
Panel %
Deviation
num_rows > 0): ?>
fetch_assoc()): ?>
0 ?
(($panel_percentage - $target_percentage) / $target_percentage) * 100 :
0;
// Determine class for deviation
$deviationClass = abs($deviation) > 10 ? 'high-deviation' :
(abs($deviation) > 5 ? 'medium-deviation' : 'low-deviation');
?>
%
%
0 ? '+' : '';
echo $sign . number_format($deviation, 2) . '%';
?>
No combinations found
-------------------- END OF FILE --------------------
### FILE 4: syndia.kreahealthcare.com/calculate_available_samples.php
- Type: PHP
- Size: 3.59 KB
- Path: syndia.kreahealthcare.com
- Name: calculate_available_samples.php
------------------------------------------------------------
isLoggedIn()) {
die(json_encode(['success' => false, 'message' => 'Unauthorized']));
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die(json_encode(['success' => false, 'message' => 'Invalid request method']));
}
$db = Database::getInstance();
$project_id = isset($_POST['project_id']) ? (int)$_POST['project_id'] : 0;
if (!$project_id) {
die(json_encode(['success' => false, 'message' => 'Invalid project ID']));
}
// Verify user has access to this project
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
die(json_encode(['success' => false, 'message' => 'Access denied']));
}
// Get all previously used panelist IDs in this project's selections
$stmt = $db->prepare("
SELECT DISTINCT panelist_id
FROM selection_members sm
JOIN selections s ON sm.selection_id = s.id
WHERE s.project_id = ?
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$used_panelists_result = $stmt->get_result();
$used_panelists = [];
while ($row = $used_panelists_result->fetch_assoc()) {
$used_panelists[] = $row['panelist_id'];
}
// Build WHERE clause based on filter criteria
$where_conditions = [];
// If we have used panelists, exclude them
if (!empty($used_panelists)) {
$used_panelists_str = "'" . implode("','", $used_panelists) . "'";
$where_conditions[] = "panelist_id NOT IN ($used_panelists_str)";
}
// Process all form inputs
$attributes = $db->query("SELECT id, name, choice_type FROM attributes ORDER BY created_at ASC");
while ($attr = $attributes->fetch_assoc()) {
$attr_id = $attr['id'];
if ($attr['choice_type'] === 'single') {
// Single choice attributes
if (isset($_POST["attr_{$attr_id}"]) && !empty($_POST["attr_{$attr_id}"])) {
$value = $db->escape($_POST["attr_{$attr_id}"]);
$where_conditions[] = "JSON_UNQUOTE(JSON_EXTRACT(attribute_values, '$.{$attr_id}')) = '{$value}'";
}
} else if ($attr['choice_type'] === 'multiple') {
// Multiple choice attributes
if (isset($_POST["attr_{$attr_id}"]) && is_array($_POST["attr_{$attr_id}"]) && !empty($_POST["attr_{$attr_id}"])) {
$values = array_map(function($value) use ($db) {
return $db->escape($value);
}, $_POST["attr_{$attr_id}"]);
$or_conditions = [];
foreach ($values as $value) {
// Use JSON_CONTAINS to check if array contains the value
$or_conditions[] = "JSON_CONTAINS(attribute_values, '\"{$value}\"', '$.{$attr_id}')";
}
$where_conditions[] = '(' . implode(' OR ', $or_conditions) . ')';
}
}
}
// For debugging
error_log("Available samples query conditions: " . implode(' AND ', $where_conditions));
// Build the SQL query to get eligible panelists
$sql = "SELECT COUNT(*) as available_samples FROM panel_data";
if (!empty($where_conditions)) {
$sql .= " WHERE " . implode(' AND ', $where_conditions);
}
error_log("Available samples SQL: " . $sql);
$result = $db->query($sql);
if (!$result) {
die(json_encode([
'success' => false,
'message' => 'Error calculating available samples: ' . $db->getLastError()
]));
}
$available_samples = $result->fetch_assoc()['available_samples'];
echo json_encode([
'success' => true,
'available_samples' => (int)$available_samples
]);
-------------------- END OF FILE --------------------
### FILE 5: syndia.kreahealthcare.com/calculate_panel_alignment.php
- Type: PHP
- Size: 7.94 KB
- Path: syndia.kreahealthcare.com
- Name: calculate_panel_alignment.php
------------------------------------------------------------
isLoggedIn()) {
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$db = Database::getInstance();
$currentUser = $auth->getCurrentUser();
try {
// Get total panel members count
$panelCountResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
$totalPanelists = $panelCountResult ? $panelCountResult->fetch_assoc()['count'] : 0;
// If no panel data, alignment score is 0%
if ($totalPanelists == 0) {
$alignment_score = 0;
$message = 'No panel data available';
} else {
// Calculate actual percentages for each statistic combination first
updateActualPercentages($db, $totalPanelists);
// Now calculate alignment score using Root Mean Square Error (RMSE) method
$alignmentResult = calculateStatisticAlignmentScoreWithStats($db);
$alignment_score = $alignmentResult['score'];
$rmse = $alignmentResult['rmse'];
$combinationsCount = $alignmentResult['combinations_count'];
$message = "RMS-based alignment calculated from {$combinationsCount} combinations (RMSE: " . number_format($rmse, 3) . ")";
}
// Cache the result in session
$_SESSION['cached_alignment_score'] = $alignment_score;
$_SESSION['cached_alignment_timestamp'] = time();
// Format timestamp
$calculated_time = new DateTime();
$calculated_time->setTimezone(new DateTimeZone('Asia/Kolkata'));
$formatted_time = $calculated_time->format('M d, Y H:i');
echo json_encode([
'success' => true,
'score' => number_format($alignment_score, 2),
'total_panelists' => $totalPanelists,
'calculated_at' => $formatted_time,
'calculated_by' => $currentUser['full_name'],
'message' => $message
]);
} catch (Exception $e) {
error_log("Error calculating panel alignment score: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => 'Failed to calculate alignment score: ' . $e->getMessage()
]);
}
/**
* Update actual percentages for all statistic combinations
*/
function updateActualPercentages($db, $totalPanelists) {
// Get all statistic combinations
$combinationsQuery = $db->query("
SELECT
sc.id,
sc.combination_values,
GROUP_CONCAT(sa.attribute_id ORDER BY sa.id) as attribute_ids
FROM statistic_combinations sc
JOIN statistic_attributes sa ON sc.statistic_id = sa.statistic_id
WHERE sc.percentage > 0
GROUP BY sc.id
");
if (!$combinationsQuery) {
return;
}
while ($combination = $combinationsQuery->fetch_assoc()) {
$combinationId = $combination['id'];
$combinationValues = json_decode($combination['combination_values'], true);
$attributeIds = explode(',', $combination['attribute_ids']);
if (!is_array($combinationValues) || count($combinationValues) != count($attributeIds)) {
continue;
}
// Build query to count panel members matching this combination
$whereConditions = [];
$params = [];
$types = '';
for ($i = 0; $i < count($attributeIds); $i++) {
$attrId = trim($attributeIds[$i]);
$value = $combinationValues[$i];
$whereConditions[] = "JSON_EXTRACT(attribute_values, '$.\"$attrId\"') = ?";
$params[] = $value;
$types .= 's';
}
if (!empty($whereConditions)) {
$whereClause = implode(' AND ', $whereConditions);
$countQuery = "SELECT COUNT(*) as count FROM panel_data WHERE $whereClause";
$stmt = $db->prepare($countQuery);
if (!empty($params)) {
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
$result = $stmt->get_result();
$actualCount = $result->fetch_assoc()['count'];
// Calculate actual percentage
$actualPercentage = ($actualCount / $totalPanelists) * 100;
// Update the statistic_combinations table
$updateStmt = $db->prepare("UPDATE statistic_combinations SET actual_percentage = ? WHERE id = ?");
$updateStmt->bind_param('di', $actualPercentage, $combinationId);
$updateStmt->execute();
$stmt->close();
$updateStmt->close();
}
}
}
/**
* Calculate alignment score using Root Mean Square (RMS) method
* Based on statistic check data (Target % vs Panel % deviations)
* Returns 100% when all targets match perfectly, 0% when completely misaligned
*/
function calculateStatisticAlignmentScore($db) {
$result = calculateStatisticAlignmentScoreWithStats($db);
return $result['score'];
}
/**
* Enhanced RMS calculation that returns additional mathematical statistics
*/
function calculateStatisticAlignmentScoreWithStats($db) {
// Get all combinations with their target and actual percentages
$alignmentQuery = $db->query("
SELECT
percentage as target_percentage,
actual_percentage
FROM statistic_combinations
WHERE percentage > 0
AND actual_percentage IS NOT NULL
");
if (!$alignmentQuery || $alignmentQuery->num_rows == 0) {
// No statistical requirements = perfect alignment
return [
'score' => 100,
'rmse' => 0,
'combinations_count' => 0,
'mean_absolute_error' => 0
];
}
$squaredDeviations = [];
$absoluteDeviations = [];
$combinationCount = 0;
// Step 1: Calculate squared deviations and absolute deviations for each combination
while ($row = $alignmentQuery->fetch_assoc()) {
$targetPercentage = floatval($row['target_percentage']);
$actualPercentage = floatval($row['actual_percentage']);
if ($targetPercentage <= 0) {
continue; // Skip invalid targets
}
// Calculate deviation (actual - target)
$deviation = $actualPercentage - $targetPercentage;
// Square the deviation for RMSE calculation
$squaredDeviation = $deviation * $deviation;
$squaredDeviations[] = $squaredDeviation;
// Absolute deviation for MAE calculation
$absoluteDeviations[] = abs($deviation);
$combinationCount++;
}
if ($combinationCount == 0) {
return [
'score' => 100,
'rmse' => 0,
'combinations_count' => 0,
'mean_absolute_error' => 0
];
}
// Step 2: Calculate Mean Squared Error (MSE)
$meanSquaredError = array_sum($squaredDeviations) / $combinationCount;
// Step 3: Calculate Root Mean Square Error (RMSE)
$rmse = sqrt($meanSquaredError);
// Step 4: Calculate Mean Absolute Error (MAE) for additional insight
$mae = array_sum($absoluteDeviations) / $combinationCount;
// Step 5: Convert RMSE to alignment score (0-100%)
// SIMPLIFIED FORMULA AS REQUESTED: 100% - RMSE = Alignment Score
// Perfect alignment: RMSE = 0 → Score = 100%
// Poor alignment: Higher RMSE → Lower score
$alignmentScore = max(0, 100 - $rmse);
return [
'score' => round($alignmentScore, 2),
'rmse' => $rmse,
'combinations_count' => $combinationCount,
'mean_absolute_error' => $mae
];
}
/**
* Get total count of statistic combinations for informational purposes
*/
function getTotalCombinationsCount($db) {
$countResult = $db->query("SELECT COUNT(*) as count FROM statistic_combinations WHERE percentage > 0");
return $countResult ? $countResult->fetch_assoc()['count'] : 0;
}
?>
-------------------- END OF FILE --------------------
### FILE 6: syndia.kreahealthcare.com/check_generation_progress.php
- Type: PHP
- Size: 1021 B
- Path: syndia.kreahealthcare.com
- Name: check_generation_progress.php
------------------------------------------------------------
isLoggedIn()) {
echo json_encode([
'error' => 'Unauthorized'
]);
exit;
}
$selection_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$selection_id) {
echo json_encode([
'error' => 'Invalid selection ID'
]);
exit;
}
// Read the progress from the temp file
$progress_file = sys_get_temp_dir() . '/syndia_progress_' . $selection_id . '.json';
if (file_exists($progress_file)) {
$progress_data = json_decode(file_get_contents($progress_file), true);
echo json_encode($progress_data);
} else {
echo json_encode([
'progress' => 0,
'processed' => 0,
'success' => 0,
'error' => 0,
'total' => 0,
'status' => 'Initializing...',
'completed' => false
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 7: syndia.kreahealthcare.com/check_progress.php
- Type: PHP
- Size: 5.89 KB
- Path: syndia.kreahealthcare.com
- Name: check_progress.php
------------------------------------------------------------
📊 OptimAIze Progress Report";
echo "";
try {
$db = Database::getInstance();
// Get current status
$totalResult = $db->query("SELECT COUNT(*) as total FROM panel_directives");
$totalDirectives = $totalResult->fetch_assoc()['total'];
$checkedResult = $db->query("SELECT COUNT(*) as checked FROM panel_directives WHERE llm_checked = 1");
$checkedDirectives = $checkedResult->fetch_assoc()['checked'];
$uncheckedResult = $db->query("SELECT COUNT(*) as unchecked FROM panel_directives WHERE llm_checked = 0");
$uncheckedDirectives = $uncheckedResult->fetch_assoc()['unchecked'];
$impossibleResult = $db->query("SELECT COUNT(*) as impossible FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1");
$impossibleDirectives = $impossibleResult->fetch_assoc()['impossible'];
echo "
📈 Processing Progress ";
echo "✅ Total Combinations: " . number_format($totalDirectives) . "
";
echo "✅ Completed: " . number_format($checkedDirectives) . " (" . round(($checkedDirectives/$totalDirectives)*100, 1) . "%)
";
echo "⏳ Remaining: " . number_format($uncheckedDirectives) . " (" . round(($uncheckedDirectives/$totalDirectives)*100, 1) . "%)
";
echo "❌ Impossible Combinations Found: " . number_format($impossibleDirectives) . "
";
// Calculate progress made since last check
$previousCompleted = 2088; // From your earlier status
$newlyCompleted = $checkedDirectives - $previousCompleted;
if ($newlyCompleted > 0) {
echo "🎉 New Progress: " . number_format($newlyCompleted) . " combinations completed with your $10 credit!
";
}
// Cost estimation for remaining
$avgCostPerCombination = 0.0004; // Estimated cost per combination with gpt-4o-mini
$remainingCost = $uncheckedDirectives * $avgCostPerCombination;
echo "
💰 Cost Analysis ";
echo "💸 Estimated cost to complete remaining: $" . number_format($remainingCost, 2) . "
";
if ($remainingCost <= 20) {
echo "✅ Recommendation: Add $" . ceil($remainingCost + 5) . " in credits to complete everything
";
} else {
echo "⚠️ Alternative: Consider processing in smaller chunks
";
}
// Recent processing activity
echo "
📅 Recent Activity ";
$recentResult = $db->query("
SELECT DATE(updated_at) as date, COUNT(*) as count
FROM panel_directives
WHERE llm_checked = 1 AND updated_at >= DATE_SUB(NOW(), INTERVAL 3 DAYS)
GROUP BY DATE(updated_at)
ORDER BY date DESC
LIMIT 5
");
if ($recentResult && $recentResult->num_rows > 0) {
echo "Processing Activity (Last 3 Days):
";
while ($row = $recentResult->fetch_assoc()) {
echo "📅 {$row['date']}: {$row['count']} combinations processed
";
}
}
// Sample of impossible combinations found
echo "
🔍 Sample Impossible Combinations Found ";
$sampleResult = $db->query("
SELECT attribute1_name, choice1, attribute2_name, choice2, llm_reasoning
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 1
ORDER BY updated_at DESC
LIMIT 5
");
if ($sampleResult && $sampleResult->num_rows > 0) {
while ($row = $sampleResult->fetch_assoc()) {
echo "";
echo "❌ {$row['attribute1_name']}='{$row['choice1']}' + {$row['attribute2_name']}='{$row['choice2']}' ";
echo "Reason: " . htmlspecialchars($row['llm_reasoning']);
echo "
";
}
} else {
echo "No impossible combinations found yet (or none stored with reasoning)
";
}
} catch (Exception $e) {
echo "Error: " . htmlspecialchars($e->getMessage()) . "
";
}
echo "
🚀 Next Steps ";
echo "";
echo "
To Continue Processing: ";
echo "
";
echo "Add Credits: Go to OpenAI Billing ";
echo "Add $20-30: This should be enough to complete all remaining combinations ";
echo "Wait 10-15 minutes: For credits to become active ";
echo "Restart Analysis: Go back to OptimAIze page and click 'Start Analysis' ";
echo " ";
echo "
";
echo "";
echo "
💡 Cost-Saving Tips: ";
echo "
";
echo "Your system is working great! The processing was successful until credits ran out ";
echo "gpt-4o-mini is very cost-effective - much cheaper than GPT-4 ";
echo "Caching is active - repeated combinations won't cost extra ";
echo "Consider batch processing - add $10-20 at a time if budget is tight ";
echo " ";
echo "
";
?>
-------------------- END OF FILE --------------------
### FILE 8: syndia.kreahealthcare.com/connect_survey.php
- Type: PHP
- Size: 3.07 KB
- Path: syndia.kreahealthcare.com
- Name: connect_survey.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$surveyId = isset($_POST['survey_id']) ? (int)$_POST['survey_id'] : null;
$projectId = isset($_POST['project_id']) ? (int)$_POST['project_id'] : null;
$redirect = isset($_POST['redirect']) ? $_POST['redirect'] : null;
if (!$surveyId || !$projectId) {
throw new Exception('Survey ID and Project ID are required');
}
$db = Database::getInstance();
// Check if the project exists and user has access
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $projectId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows == 0) {
throw new Exception('Project not found or access denied');
}
// Check if the survey exists and user has access
$stmt = $db->prepare("SELECT id FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows == 0) {
throw new Exception('Survey not found or access denied');
}
// Check if already connected
$stmt = $db->prepare("SELECT id FROM project_surveys WHERE project_id = ? AND survey_id = ?");
$stmt->bind_param('ii', $projectId, $surveyId);
$stmt->execute();
if ($stmt->get_result()->num_rows > 0) {
throw new Exception('Survey is already connected to this project');
}
// Remove any existing connections for this project first (since only one survey can be connected)
$stmt = $db->prepare("DELETE FROM project_surveys WHERE project_id = ?");
$stmt->bind_param('i', $projectId);
$stmt->execute();
// Connect survey to project
$stmt = $db->prepare("INSERT INTO project_surveys (project_id, survey_id, created_by) VALUES (?, ?, ?)");
$stmt->bind_param('iii', $projectId, $surveyId, $_SESSION['user_id']);
if (!$stmt->execute()) {
throw new Exception('Failed to connect survey to project');
}
// Handle redirect or JSON response
if ($redirect) {
// Set a success message in session
$_SESSION['success_message'] = 'Survey connected successfully';
redirectTo($redirect);
exit;
} else {
// Return JSON response
header('Content-Type: application/json');
echo json_encode([
'success' => true,
'message' => 'Survey connected successfully'
]);
}
} catch (Exception $e) {
if (isset($_POST['redirect'])) {
// Set error message in session
$_SESSION['error_message'] = $e->getMessage();
redirectTo($_POST['redirect']);
exit;
} else {
// Return JSON error
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
}
?>
-------------------- END OF FILE --------------------
### FILE 9: syndia.kreahealthcare.com/conservative_optimization_processor.php
- Type: PHP
- Size: 10.25 KB
- Path: syndia.kreahealthcare.com
- Name: conservative_optimization_processor.php
------------------------------------------------------------
";
}
flush();
}
function updateProgress($processed, $total, $currentStatus = '') {
global $startTime;
try {
$db = Database::getInstance();
$elapsed = microtime(true) - $startTime;
$rate = $processed > 0 ? ($processed / ($elapsed / 3600)) : 0; // per hour
$eta = $total > $processed && $rate > 0 ? (($total - $processed) / $rate) * 3600 : 0; // in seconds
$etaFormatted = $eta > 0 ? gmdate('H:i:s', $eta) : 'Unknown';
$updateQuery = "
UPDATE optimization_analysis_state
SET processed_combinations = ?,
current_combination = ?,
processing_rate = ?,
last_update = NOW()
WHERE id = 1
";
$stmt = $db->prepare($updateQuery);
$stmt->bind_param('isd', $processed, $currentStatus, $rate);
$stmt->execute();
writeLog("Progress: $processed/$total (" . round(($processed/$total)*100, 1) . "%) | Rate: " .
round($rate, 2) . "/hour | ETA: $etaFormatted");
} catch (Exception $e) {
writeLog("Failed to update progress: " . $e->getMessage(), 'ERROR');
}
}
function safeApiCall($attr1, $choice1, $attr2, $choice2, $attempt = 1) {
$maxAttempts = MAX_RETRIES;
try {
writeLog("API Call Attempt $attempt/$maxAttempts: $attr1=$choice1 + $attr2=$choice2");
// Check if we need to wait for rate limits
$rateLimitStatus = GptHelper::getRateLimitStatus(false); // Use standard limits
if (!$rateLimitStatus['can_make_request']) {
$waitTime = $rateLimitStatus['cooldown_remaining'] + 30; // Add 30 second buffer
writeLog("Rate limit active. Waiting $waitTime seconds...", 'WARN');
sleep($waitTime);
}
// Make the actual request
$result = GptHelper::analyzeCombination($attr1, $choice1, $attr2, $choice2);
writeLog("API call successful: " . ($result['is_impossible'] ? 'IMPOSSIBLE' : 'POSSIBLE'));
return $result;
} catch (Exception $e) {
writeLog("API call attempt $attempt failed: " . $e->getMessage(), 'ERROR');
if ($attempt < $maxAttempts) {
// Exponential backoff
$backoffTime = CONSERVATIVE_DELAY * pow(EXPONENTIAL_BACKOFF_BASE, $attempt - 1);
$backoffTime = min($backoffTime, 600); // Cap at 10 minutes
writeLog("Retrying in $backoffTime seconds (exponential backoff)...", 'WARN');
sleep($backoffTime);
return safeApiCall($attr1, $choice1, $attr2, $choice2, $attempt + 1);
} else {
throw new Exception("Max retries exceeded: " . $e->getMessage());
}
}
}
// Start processing
try {
writeLog("=== Conservative OptimAIze Analysis Started ===");
writeLog("Configuration: Ultra-conservative mode - 1 request per 90 seconds");
$db = Database::getInstance();
writeLog("Database connected successfully");
// Reset GPT rate limits
GptHelper::resetRateLimit();
writeLog("Rate limits reset");
// Get total count
$countResult = $db->query("SELECT COUNT(*) as total FROM panel_directives WHERE llm_checked = 0");
$totalCount = $countResult->fetch_assoc()['total'];
if ($totalCount == 0) {
writeLog("No combinations to process. Analysis complete!");
$db->query("UPDATE optimization_analysis_state SET is_running = 0, completed_at = NOW() WHERE id = 1");
exit(0);
}
writeLog("Total combinations to analyze: $totalCount");
writeLog("Estimated time: " . round($totalCount * (CONSERVATIVE_DELAY / 3600), 1) . " hours");
// Update state to running
$db->query("UPDATE optimization_analysis_state SET is_running = 1, started_at = NOW(), total_combinations = $totalCount WHERE id = 1");
$processedCount = 0;
$successCount = 0;
$errorCount = 0;
// Main processing loop - one combination at a time
while ($processedCount < $totalCount) {
// Check if we should pause or stop
$stateResult = $db->query("SELECT is_running, should_pause FROM optimization_analysis_state WHERE id = 1");
$state = $stateResult->fetch_assoc();
if (!$state['is_running']) {
writeLog("Analysis stopped by user");
break;
}
if ($state['should_pause']) {
writeLog("Analysis paused by user. Waiting...");
sleep(30);
continue;
}
// Get next combination
$query = $db->query("
SELECT id, attribute1_name, choice1, attribute2_name, choice2
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT 1
");
if (!$query || $query->num_rows == 0) {
writeLog("No more combinations to process");
break;
}
$directive = $query->fetch_assoc();
$combinationText = "{$directive['attribute1_name']}='{$directive['choice1']}' + {$directive['attribute2_name']}='{$directive['choice2']}'";
writeLog("Processing combination ID {$directive['id']}: $combinationText");
try {
// Analyze combination with retries
$result = safeApiCall(
$directive['attribute1_name'],
$directive['choice1'],
$directive['attribute2_name'],
$directive['choice2']
);
// Update database
$stmt = $db->prepare("
UPDATE panel_directives
SET llm_checked = 1,
is_impossible = ?,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?
");
$isImpossible = $result['is_impossible'] ? 1 : 0;
$stmt->bind_param('isi', $isImpossible, $result['reasoning'], $directive['id']);
if ($stmt->execute()) {
$processedCount++;
$successCount++;
$resultText = $result['is_impossible'] ? "IMPOSSIBLE" : "POSSIBLE";
$cacheText = isset($result['cached']) && $result['cached'] ? " (cached)" : "";
writeLog("✅ SUCCESS: ID {$directive['id']} => $resultText$cacheText");
writeLog(" Reasoning: " . substr($result['reasoning'], 0, 100) . "...");
// Update progress
updateProgress($processedCount, $totalCount, $combinationText);
} else {
throw new Exception("Database update failed: " . $stmt->error);
}
} catch (Exception $e) {
$errorCount++;
writeLog("❌ FAILED: ID {$directive['id']} - " . $e->getMessage(), 'ERROR');
// Mark as checked but with error (to avoid infinite retry)
$errorStmt = $db->prepare("
UPDATE panel_directives
SET llm_checked = 1,
is_impossible = 0,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?
");
$errorReason = "Processing failed: " . $e->getMessage();
$errorStmt->bind_param('si', $errorReason, $directive['id']);
$errorStmt->execute();
$processedCount++; // Count as processed even if failed
}
// Conservative delay between requests
if ($processedCount < $totalCount) {
writeLog("Waiting " . CONSERVATIVE_DELAY . " seconds before next request...");
sleep(CONSERVATIVE_DELAY);
}
}
// Final statistics
$endTime = microtime(true);
$totalTime = $endTime - $startTime;
writeLog("=== Analysis Complete ===");
writeLog("Total processed: $processedCount");
writeLog("Successful: $successCount");
writeLog("Errors: $errorCount");
writeLog("Total time: " . gmdate('H:i:s', $totalTime));
writeLog("Success rate: " . round(($successCount / max($processedCount, 1)) * 100, 1) . "%");
// Mark as completed
$db->query("UPDATE optimization_analysis_state SET is_running = 0, completed_at = NOW(), total_processed = $processedCount WHERE id = 1");
writeLog("Analysis completed successfully!");
} catch (Exception $e) {
writeLog("FATAL ERROR: " . $e->getMessage(), 'ERROR');
try {
$db = Database::getInstance();
$db->query("UPDATE optimization_analysis_state SET is_running = 0, error_message = '" . $e->getMessage() . "' WHERE id = 1");
} catch (Exception $e2) {
writeLog("Could not update error state: " . $e2->getMessage(), 'ERROR');
}
exit(1);
}
?>
-------------------- END OF FILE --------------------
### FILE 10: syndia.kreahealthcare.com/create_selection.php
- Type: PHP
- Size: 5.8 KB
- Path: syndia.kreahealthcare.com
- Name: create_selection.php
------------------------------------------------------------
isLoggedIn()) {
$_SESSION['error_message'] = 'Unauthorized';
redirectTo('projects.php');
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$_SESSION['error_message'] = 'Invalid request method';
redirectTo('projects.php');
exit;
}
$db = Database::getInstance();
$project_id = isset($_POST['project_id']) ? (int)$_POST['project_id'] : 0;
$selection_name = isset($_POST['selection_name']) ? sanitizeInput($_POST['selection_name']) : '';
$required_size = isset($_POST['required_size']) ? (int)$_POST['required_size'] : 0;
if (!$project_id || empty($selection_name) || $required_size <= 0) {
$_SESSION['error_message'] = 'Required fields are missing';
redirectTo("manage_project.php?id=$project_id");
exit;
}
// Verify user has access to this project
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
$_SESSION['error_message'] = 'Access denied';
redirectTo('projects.php');
exit;
}
// Get all previously used panelist IDs in this project's selections
$stmt = $db->prepare("
SELECT DISTINCT panelist_id
FROM selection_members sm
JOIN selections s ON sm.selection_id = s.id
WHERE s.project_id = ?
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$used_panelists_result = $stmt->get_result();
$used_panelists = [];
while ($row = $used_panelists_result->fetch_assoc()) {
$used_panelists[] = $row['panelist_id'];
}
// Build WHERE clause based on filter criteria
$where_conditions = [];
$filter_descriptions = [];
// If we have used panelists, exclude them
if (!empty($used_panelists)) {
$used_panelists_str = "'" . implode("','", $used_panelists) . "'";
$where_conditions[] = "panelist_id NOT IN ($used_panelists_str)";
}
// Process filter criteria from attributes
$attributes = $db->query("SELECT id, name, choice_type FROM attributes ORDER BY created_at ASC");
while ($attr = $attributes->fetch_assoc()) {
$attr_id = $attr['id'];
if ($attr['choice_type'] === 'single') {
// Single choice attributes
if (isset($_POST["attr_{$attr_id}"]) && !empty($_POST["attr_{$attr_id}"])) {
$value = $db->escape($_POST["attr_{$attr_id}"]);
$where_conditions[] = "JSON_UNQUOTE(JSON_EXTRACT(attribute_values, '$.{$attr_id}')) = '{$value}'";
$filter_descriptions[] = "{$attr['name']}: {$value}";
}
} else if ($attr['choice_type'] === 'multiple') {
// Multiple choice attributes
if (isset($_POST["attr_{$attr_id}"]) && is_array($_POST["attr_{$attr_id}"]) && !empty($_POST["attr_{$attr_id}"])) {
$values = array_map(function($value) use ($db) {
return $db->escape($value);
}, $_POST["attr_{$attr_id}"]);
$or_conditions = [];
foreach ($values as $value) {
// Use JSON_CONTAINS to check if array contains the value
$or_conditions[] = "JSON_CONTAINS(attribute_values, '\"{$value}\"', '$.{$attr_id}')";
}
$where_conditions[] = '(' . implode(' OR ', $or_conditions) . ')';
$filter_descriptions[] = "{$attr['name']}: " . implode(' OR ', $values);
}
}
}
// Log the SQL query for debugging
error_log("Selection filter conditions: " . implode(' AND ', $where_conditions));
// Build the SQL query to get eligible panelists
$sql = "SELECT panelist_id FROM panel_data";
if (!empty($where_conditions)) {
$sql .= " WHERE " . implode(' AND ', $where_conditions);
}
$sql .= " ORDER BY RAND() LIMIT $required_size";
error_log("Selection SQL query: " . $sql);
$result = $db->query($sql);
if (!$result) {
$_SESSION['error_message'] = 'Error querying panel data: ' . $db->getLastError();
redirectTo("manage_project.php?id=$project_id");
exit;
}
// Check if we have enough panelists
$panelists = [];
while ($row = $result->fetch_assoc()) {
$panelists[] = $row['panelist_id'];
}
if (count($panelists) < $required_size) {
$_SESSION['error_message'] = 'Not enough eligible panelists found. Only ' . count($panelists) . ' available.';
redirectTo("manage_project.php?id=$project_id");
exit;
}
// Begin transaction
$db->query("START TRANSACTION");
try {
// Create the selection record
$filters_text = implode(', ', $filter_descriptions);
$stmt = $db->prepare("
INSERT INTO selections (
project_id, name, sample_size, filters, created_by
) VALUES (?, ?, ?, ?, ?)
");
$stmt->bind_param('isisi', $project_id, $selection_name, $required_size, $filters_text, $_SESSION['user_id']);
if (!$stmt->execute()) {
throw new Exception("Failed to create selection: " . $db->getLastError());
}
$selection_id = $db->getLastInsertId();
// Insert selection members
$stmt = $db->prepare("
INSERT INTO selection_members (selection_id, panelist_id) VALUES (?, ?)
");
foreach ($panelists as $panelist_id) {
$stmt->bind_param('is', $selection_id, $panelist_id);
if (!$stmt->execute()) {
throw new Exception("Failed to add selection member: " . $db->getLastError());
}
}
// Commit the transaction
$db->query("COMMIT");
$_SESSION['success_message'] = "Selection '$selection_name' created successfully with $required_size panelists";
redirectTo("manage_project.php?id=$project_id");
} catch (Exception $e) {
// Rollback on error
$db->query("ROLLBACK");
$_SESSION['error_message'] = $e->getMessage();
redirectTo("manage_project.php?id=$project_id");
}
?>
-------------------- END OF FILE --------------------
### FILE 11: syndia.kreahealthcare.com/dashboard.php
- Type: PHP
- Size: 17.35 KB
- Path: syndia.kreahealthcare.com
- Name: dashboard.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance(); // Add this line to initialize the database connection
?>
Dashboard |
Attributes
query("SELECT COUNT(*) as count FROM attributes");
$attr_count = $attr_count_query ? $attr_count_query->fetch_assoc()['count'] : 0;
?>
Total registered attributes
Statistical Points
query("SELECT COUNT(*) as count FROM statistics");
$stats_count = $stats_query ? $stats_query->fetch_assoc()['count'] : 0;
$combinations_query = $db->query("SELECT COUNT(*) as count FROM statistic_combinations");
$combinations_count = $combinations_query ? $combinations_query->fetch_assoc()['count'] : 0;
$total_stats = $stats_count + $combinations_count;
?>
statistics, combinations
Panel Size
query("SELECT COUNT(*) as count FROM panel_data");
$panel_count = $panel_count_query ? $panel_count_query->fetch_assoc()['count'] : 0;
?>
Syndians
Alignment Score
query("SELECT COUNT(*) as count FROM panel_data");
$panelCount = $countCheck->fetch_assoc()['count'];
if ($panelCount == 0) {
$alignmentScore = 0; // No alignment for empty panel
} else {
// Make sure statistic_combinations table has actual_percentage column
$columnCheck = $db->query("SHOW COLUMNS FROM statistic_combinations LIKE 'actual_percentage'");
if ($columnCheck->num_rows === 0) {
// If column doesn't exist, alignment score is not available
$alignmentScore = 'N/A';
} else {
// Calculate RMSE (Root Mean Square Error)
$query = $db->query("
SELECT SQRT(AVG(POW(percentage - actual_percentage, 2))) as rmse
FROM statistic_combinations
WHERE actual_percentage IS NOT NULL
");
if ($query && $row = $query->fetch_assoc()) {
$rmse = $row['rmse'] ?? 100;
// Convert RMSE to alignment score (100 - RMSE)
// Cap at 0 to avoid negative scores
$alignmentScore = max(0, 100 - $rmse);
} else {
$alignmentScore = 'N/A';
}
}
}
// Determine color class based on score
$scoreClass = ($alignmentScore !== 'N/A' && $alignmentScore >= 95) ? 'score-good' : 'score-bad';
?>
Panel quality (using RMSE)
-------------------- END OF FILE --------------------
### FILE 12: syndia.kreahealthcare.com/db.php
- Type: PHP
- Size: 1.54 KB
- Path: syndia.kreahealthcare.com
- Name: db.php
------------------------------------------------------------
connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($this->connection->connect_error) {
throw new Exception("Connection failed: " . $this->connection->connect_error);
}
$this->connection->set_charset("utf8mb4");
} catch (Exception $e) {
die("Database connection failed: " . $e->getMessage());
}
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new Database();
}
return self::$instance;
}
public function query($sql) {
return $this->connection->query($sql);
}
public function prepare($sql) {
return $this->connection->prepare($sql);
}
public function escape($value) {
return $this->connection->real_escape_string($value);
}
public function getLastError() {
return $this->connection->error;
}
public function getLastInsertId() {
return $this->connection->insert_id;
}
public function getConnection() {
return $this->connection;
}
/**
* Get the number of affected rows from the last query
* @return int The number of rows affected by the last INSERT, UPDATE, REPLACE or DELETE query
*/
public function getAffectedRows() {
return $this->connection->affected_rows;
}
}
-------------------- END OF FILE --------------------
### FILE 13: syndia.kreahealthcare.com/delete_directive.php
- Type: PHP
- Size: 1.06 KB
- Path: syndia.kreahealthcare.com
- Name: delete_directive.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['id'])) {
throw new Exception('Missing directive ID');
}
$id = (int)$input['id'];
$db = Database::getInstance();
// Delete directive
$stmt = $db->prepare("DELETE FROM panel_directives WHERE id = ?");
$stmt->bind_param('i', $id);
if (!$stmt->execute()) {
throw new Exception('Failed to delete directive');
}
if ($stmt->affected_rows === 0) {
throw new Exception('Directive not found');
}
echo json_encode([
'success' => true,
'message' => 'Directive deleted successfully'
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 14: syndia.kreahealthcare.com/delete_selection.php
- Type: PHP
- Size: 2.37 KB
- Path: syndia.kreahealthcare.com
- Name: delete_selection.php
------------------------------------------------------------
isLoggedIn()) {
$_SESSION['error_message'] = 'Unauthorized';
redirectTo('projects.php');
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$_SESSION['error_message'] = 'Invalid request method';
redirectTo('projects.php');
exit;
}
$db = Database::getInstance();
$selection_id = isset($_POST['selection_id']) ? (int)$_POST['selection_id'] : 0;
$project_id = isset($_POST['project_id']) ? (int)$_POST['project_id'] : 0;
if (!$selection_id || !$project_id) {
$_SESSION['error_message'] = 'Required fields are missing';
redirectTo("manage_project.php?id=$project_id");
exit;
}
// Verify user has access to this selection and project
$stmt = $db->prepare("
SELECT s.name
FROM selections s
JOIN projects p ON s.project_id = p.id
WHERE s.id = ? AND p.id = ? AND p.created_by = ?
");
$stmt->bind_param('iii', $selection_id, $project_id, $_SESSION['user_id']);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
$_SESSION['error_message'] = 'Selection not found or access denied';
redirectTo("manage_project.php?id=$project_id");
exit;
}
$selection_name = $result->fetch_assoc()['name'];
// Begin transaction
$db->query("START TRANSACTION");
try {
// First delete selection members
$stmt = $db->prepare("DELETE FROM selection_members WHERE selection_id = ?");
$stmt->bind_param('i', $selection_id);
if (!$stmt->execute()) {
throw new Exception("Failed to delete selection members: " . $db->getLastError());
}
// Then delete the selection
$stmt = $db->prepare("DELETE FROM selections WHERE id = ?");
$stmt->bind_param('i', $selection_id);
if (!$stmt->execute()) {
throw new Exception("Failed to delete selection: " . $db->getLastError());
}
// Commit the transaction
$db->query("COMMIT");
$_SESSION['success_message'] = "Selection '$selection_name' has been deleted successfully";
redirectTo("manage_project.php?id=$project_id");
} catch (Exception $e) {
// Rollback on error
$db->query("ROLLBACK");
$_SESSION['error_message'] = $e->getMessage();
redirectTo("manage_project.php?id=$project_id");
}
?>
-------------------- END OF FILE --------------------
### FILE 15: syndia.kreahealthcare.com/delete_survey_question.php
- Type: PHP
- Size: 2.03 KB
- Path: syndia.kreahealthcare.com
- Name: delete_survey_question.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Get input data
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['question_id'])) {
throw new Exception('Question ID is required');
}
$questionId = (int)$input['question_id'];
$db = Database::getInstance();
// Get survey ID for this question
$stmt = $db->prepare("SELECT survey_id FROM survey_questions WHERE id = ?");
$stmt->bind_param('i', $questionId);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
throw new Exception('Question not found');
}
$surveyId = $result->fetch_assoc()['survey_id'];
// Verify user has access to this survey
$stmt = $db->prepare("SELECT id FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
throw new Exception('Access denied');
}
// Delete the question
$stmt = $db->prepare("DELETE FROM survey_questions WHERE id = ?");
$stmt->bind_param('i', $questionId);
if (!$stmt->execute()) {
throw new Exception('Failed to delete question');
}
// Reorder remaining questions
$stmt = $db->prepare("
SET @rank = 0;
UPDATE survey_questions
SET question_order = @rank := @rank + 1
WHERE survey_id = ?
ORDER BY question_order
");
$stmt->bind_param('i', $surveyId);
$stmt->execute();
echo json_encode([
'success' => true,
'message' => 'Question deleted successfully'
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 16: syndia.kreahealthcare.com/delete_survey.php
- Type: PHP
- Size: 963 B
- Path: syndia.kreahealthcare.com
- Name: delete_survey.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Get and validate input
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['survey_id'])) {
throw new Exception('Survey ID is required');
}
$surveyManager = SurveyManager::getInstance();
$result = $surveyManager->deleteSurvey($input['survey_id'], $_SESSION['user_id']);
if (!$result['success']) {
throw new Exception($result['error']);
}
echo json_encode([
'success' => true,
'message' => 'Survey deleted successfully'
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 17: syndia.kreahealthcare.com/diagnostic_optimaize.php
- Type: PHP
- Size: 8.31 KB
- Path: syndia.kreahealthcare.com
- Name: diagnostic_optimaize.php
------------------------------------------------------------
🔍 OptimAIze Diagnostic Script";
echo "";
try {
$db = Database::getInstance();
echo "✅ Database connected
";
// Check 1: Current analysis state
echo "1. Current Analysis State ";
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
if ($stateQuery && $stateQuery->num_rows > 0) {
$state = $stateQuery->fetch_assoc();
echo "" . json_encode($state, JSON_PRETTY_PRINT) . " ";
if ($state['is_running']) {
echo "⚠️ Analysis is marked as running
";
} else {
echo "ℹ️ Analysis is not running
";
}
} else {
echo "⚠️ No analysis state found - creating initial state
";
$db->query("INSERT INTO optimization_analysis_state (total_combinations, processed_combinations, is_running) VALUES (0, 0, 0)");
}
// Check 2: Panel directives status
echo "2. Panel Directives Status ";
$totalQuery = $db->query("SELECT COUNT(*) as total FROM panel_directives");
$total = $totalQuery->fetch_assoc()['total'];
$processedQuery = $db->query("SELECT COUNT(*) as processed FROM panel_directives WHERE llm_checked = 1");
$processed = $processedQuery->fetch_assoc()['processed'];
$pendingQuery = $db->query("SELECT COUNT(*) as pending FROM panel_directives WHERE llm_checked = 0");
$pending = $pendingQuery->fetch_assoc()['pending'];
echo "📊 Total combinations: " . number_format($total) . "
";
echo "📊 Processed: " . number_format($processed) . "
";
echo "📊 Pending: " . number_format($pending) . "
";
if ($pending === 0) {
echo "✅ All combinations have been processed!
";
} else {
echo "⚠️ $pending combinations still need processing
";
}
// Check 3: Test database updates
echo "3. Test Database Updates ";
echo "Test Database Update ";
echo "
";
// Check 4: Test single API call
echo "4. Test API Call ";
echo "Test Single API Call ";
echo "
";
// Check 5: Show recent log entries
echo "5. Recent Log Entries ";
$logFile = 'logs/processor_debug.log';
if (file_exists($logFile)) {
$logContent = file_get_contents($logFile);
$lines = explode("\n", $logContent);
$recentLines = array_slice($lines, -20); // Last 20 lines
echo "" . htmlspecialchars(implode("\n", $recentLines)) . " ";
} else {
echo "⚠️ No log file found at: $logFile
";
}
// Check 6: Manual processing test
echo "6. Manual Processing Test ";
if ($pending > 0) {
echo "Process Single Batch (Test) ";
echo "
";
} else {
echo "ℹ️ No pending combinations to test
";
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
?>
query("UPDATE optimization_analysis_state SET processed_combinations = processed_combinations + 1 WHERE id = 1");
if ($testUpdate) {
echo "✅ Database update successful
";
// Get current state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state WHERE id = 1");
if ($stateQuery) {
$state = $stateQuery->fetch_assoc();
echo "" . json_encode($state, JSON_PRETTY_PRINT) . " ";
}
} else {
echo "❌ Database update failed: " . $db->error . "
";
}
} catch (Exception $e) {
echo "❌ Exception: " . htmlspecialchars($e->getMessage()) . "
";
}
exit;
}
if ($_GET['action'] === 'test_api') {
try {
$result = GptHelper::analyzeCombination('Age', '5 years', 'Education', 'PhD');
if ($result['success']) {
echo "✅ API call successful
";
echo "Result: " . ($result['is_impossible'] ? 'IMPOSSIBLE' : 'POSSIBLE') . "
";
echo "Reasoning: " . htmlspecialchars($result['reasoning']) . "
";
if (isset($result['daily_cost'])) {
echo "Daily cost: $" . number_format($result['daily_cost'], 4) . "
";
}
} else {
echo "❌ API call failed: " . htmlspecialchars($result['error']) . "
";
}
} catch (Exception $e) {
echo "❌ Exception: " . htmlspecialchars($e->getMessage()) . "
";
}
exit;
}
}
?>
-------------------- END OF FILE --------------------
### FILE 18: syndia.kreahealthcare.com/direct_gpt_test.php
- Type: PHP
- Size: 11.87 KB
- Path: syndia.kreahealthcare.com
- Name: direct_gpt_test.php
------------------------------------------------------------
Direct GPT Test
🧪 Direct GPT Test
⚠️ Critical Test: This will definitively show if your OpenAI API is working.
If successful, you WILL see usage in your OpenAI dashboard within 1-2 hours.
🔑 API Key Check
✅ API Key Found: $keyPreview (Length: $keyLength chars)
";
if (!str_starts_with(OPENAI_API_KEY, 'sk-')) {
echo "
❌ Invalid API key format - should start with 'sk-'
";
}
} else {
echo "
❌ No OpenAI API key found
";
}
?>
🤖 Direct API Test
🚀 Make Direct GPT API Call
🔧 GptHelper Test
🔧 Test GptHelper Class
'gpt-4',
'messages' => [
[
'role' => 'user',
'content' => 'Respond with exactly: "Direct API test successful at ' . date('H:i:s') . '"'
]
],
'max_tokens' => 50,
'temperature' => 0.1
];
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . OPENAI_API_KEY,
'Content-Type: application/json'
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
throw new Exception("cURL Error: $curlError");
}
if ($httpCode !== 200) {
throw new Exception("HTTP Error $httpCode: $response");
}
$result = json_decode($response, true);
if (!$result || !isset($result['choices'][0]['message']['content'])) {
throw new Exception("Invalid API response: $response");
}
ob_clean();
echo json_encode([
'success' => true,
'response' => $result['choices'][0]['message']['content'],
'usage' => $result['usage'] ?? ['prompt_tokens' => 0, 'completion_tokens' => 0, 'total_tokens' => 0],
'http_code' => $httpCode
]);
} elseif ($_GET['action'] === 'gpt_helper') {
// Test using GptHelper class
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
if (!class_exists('GptHelper')) {
throw new Exception('GptHelper class not found');
}
$messages = [
[
'role' => 'user',
'content' => 'Respond with exactly: "GptHelper test successful at ' . date('H:i:s') . '"'
]
];
$response = GptHelper::makeRequest($messages, 'gpt-4', 0.1);
if (!$response['success']) {
throw new Exception($response['error']);
}
ob_clean();
echo json_encode([
'success' => true,
'response' => $response['response'],
'usage' => $response['usage'] ?? 'Not provided'
]);
}
} catch (Exception $e) {
ob_clean();
echo json_encode([
'success' => false,
'error' => $e->getMessage(),
'http_code' => $httpCode ?? null
]);
}
exit;
}
?>
-------------------- END OF FILE --------------------
### FILE 19: syndia.kreahealthcare.com/disconnect_survey.php
- Type: PHP
- Size: 2.12 KB
- Path: syndia.kreahealthcare.com
- Name: disconnect_survey.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$connectionId = isset($_POST['connection_id']) ? (int)$_POST['connection_id'] : null;
$redirect = isset($_POST['redirect']) ? $_POST['redirect'] : null;
if (!$connectionId) {
throw new Exception('Connection ID is required');
}
$db = Database::getInstance();
// Check if the connection exists and user has access
$stmt = $db->prepare("
SELECT ps.*
FROM project_surveys ps
JOIN projects p ON ps.project_id = p.id
WHERE ps.id = ? AND p.created_by = ?
");
$stmt->bind_param('ii', $connectionId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows == 0) {
throw new Exception('Connection not found or access denied');
}
// Disconnect (delete the connection)
$stmt = $db->prepare("DELETE FROM project_surveys WHERE id = ?");
$stmt->bind_param('i', $connectionId);
if (!$stmt->execute()) {
throw new Exception('Failed to disconnect survey from project');
}
// Handle redirect or JSON response
if ($redirect) {
// Set a success message in session
$_SESSION['success_message'] = 'Survey disconnected successfully';
redirectTo($redirect);
exit;
} else {
// Return JSON response
header('Content-Type: application/json');
echo json_encode([
'success' => true,
'message' => 'Survey disconnected successfully'
]);
}
} catch (Exception $e) {
if (isset($_POST['redirect'])) {
// Set error message in session
$_SESSION['error_message'] = $e->getMessage();
redirectTo($_POST['redirect']);
exit;
} else {
// Return JSON error
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
}
?>
-------------------- END OF FILE --------------------
### FILE 20: syndia.kreahealthcare.com/emergency_check.php
- Type: PHP
- Size: 7.27 KB
- Path: syndia.kreahealthcare.com
- Name: emergency_check.php
------------------------------------------------------------
🚨 Emergency Diagnostic";
echo "";
echo "PHP Version: " . PHP_VERSION . "
";
echo "Current Time: " . date('Y-m-d H:i:s') . "
";
echo "Memory Limit: " . ini_get('memory_limit') . "
";
// Test 1: Check if files exist (don't include them yet)
echo "1. File Existence Check ";
$coreFiles = [
'includes/config.php',
'includes/db.php',
'includes/GptHelper.php',
'includes/auth.php',
'login.php',
'dashboard.php',
'index.php'
];
foreach ($coreFiles as $file) {
if (file_exists($file)) {
$size = filesize($file);
echo "✅ $file exists ($size bytes)
";
} else {
echo "❌ $file missing
";
}
}
// Test 2: Check file contents for syntax errors
echo "2. File Content Check ";
function checkPHPSyntax($file) {
if (!file_exists($file)) return "File not found";
$content = file_get_contents($file);
// Check for basic PHP syntax
if (strpos($content, '&1");
unlink($temp);
if ($output && strpos($output, 'No syntax errors') === false) {
return "Syntax error: " . trim($output);
}
return "OK";
}
$testFiles = ['includes/config.php', 'includes/db.php', 'includes/GptHelper.php'];
foreach ($testFiles as $file) {
$result = checkPHPSyntax($file);
if ($result === "OK") {
echo "✅ $file syntax OK
";
} else {
echo "❌ $file: $result
";
}
}
// Test 3: Try including config.php only
echo "3. Config Test ";
try {
ob_start();
include 'includes/config.php';
$output = ob_get_clean();
if (defined('DB_HOST')) {
echo "✅ Config loaded successfully
";
echo "DB_HOST: " . DB_HOST . "
";
echo "DB_NAME: " . DB_NAME . "
";
} else {
echo "❌ Config loaded but constants not defined
";
}
if (!empty($output)) {
echo "❌ Config produced output: " . htmlspecialchars($output) . "
";
}
} catch (ParseError $e) {
echo "❌ Config parse error: " . $e->getMessage() . "
";
} catch (Error $e) {
echo "❌ Config fatal error: " . $e->getMessage() . "
";
} catch (Exception $e) {
echo "❌ Config exception: " . $e->getMessage() . "
";
}
// Test 4: Try including db.php only
echo "4. Database Class Test ";
try {
ob_start();
include 'includes/db.php';
$output = ob_get_clean();
if (class_exists('Database')) {
echo "✅ Database class loaded
";
} else {
echo "❌ Database class not found
";
}
if (!empty($output)) {
echo "❌ DB file produced output: " . htmlspecialchars($output) . "
";
}
} catch (ParseError $e) {
echo "❌ DB parse error: " . $e->getMessage() . "
";
} catch (Error $e) {
echo "❌ DB fatal error: " . $e->getMessage() . "
";
} catch (Exception $e) {
echo "❌ DB exception: " . $e->getMessage() . "
";
}
// Test 5: Try including GptHelper.php only
echo "5. GptHelper Test ";
try {
ob_start();
include 'includes/GptHelper.php';
$output = ob_get_clean();
if (class_exists('GptHelper')) {
echo "✅ GptHelper class loaded
";
} else {
echo "❌ GptHelper class not found
";
}
if (!empty($output)) {
echo "❌ GptHelper produced output: " . htmlspecialchars($output) . "
";
}
} catch (ParseError $e) {
echo "❌ GptHelper parse error: " . $e->getMessage() . "
";
} catch (Error $e) {
echo "❌ GptHelper fatal error: " . $e->getMessage() . "
";
} catch (Exception $e) {
echo "❌ GptHelper exception: " . $e->getMessage() . "
";
}
// Test 6: Check error log
echo "6. Recent Error Log ";
$errorLog = ini_get('error_log');
if ($errorLog && file_exists($errorLog)) {
$errors = file_get_contents($errorLog);
$recentErrors = array_slice(explode("\n", $errors), -10);
echo "Recent errors:
";
echo "" . htmlspecialchars(implode("\n", $recentErrors)) . " ";
} else {
echo "No error log found at: $errorLog
";
}
// Test 7: Check if any processes are stuck
echo "7. Database Connection Test ";
try {
if (defined('DB_HOST') && class_exists('Database')) {
$db = Database::getInstance();
$result = $db->query("SELECT 1 as test");
if ($result) {
echo "✅ Database connection works
";
// Check optimization state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state LIMIT 1");
if ($stateQuery && $stateQuery->num_rows > 0) {
$state = $stateQuery->fetch_assoc();
echo "Analysis running: " . ($state['is_running'] ? 'YES' : 'NO') . "
";
if ($state['is_running']) {
echo "⚠️ Analysis process is still marked as running - this might be causing issues
";
echo "";
}
}
} else {
echo "❌ Database query failed
";
}
}
} catch (Exception $e) {
echo "❌ Database test error: " . $e->getMessage() . "
";
}
// Handle stop request
if (isset($_GET['stop'])) {
try {
if (defined('DB_HOST') && class_exists('Database')) {
$db = Database::getInstance();
$db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0");
echo "✅ Analysis process stopped
";
}
} catch (Exception $e) {
echo "❌ Stop failed: " . $e->getMessage() . "
";
}
}
echo "✅ Diagnostic Complete ";
echo "If this page loads, PHP is working. Check the errors above to find the issue.
";
?>
-------------------- END OF FILE --------------------
### FILE 21: syndia.kreahealthcare.com/enhanced_get_optimization_progress.php
- Type: PHP
- Size: 5.11 KB
- Path: syndia.kreahealthcare.com
- Name: enhanced_get_optimization_progress.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$db = Database::getInstance();
// Get current analysis state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
// Get real-time statistics
$stats = getCurrentStats($db);
// Calculate processing rate (combinations per minute)
$processingRate = calculateProcessingRate($db);
// Estimate time remaining
$timeRemaining = estimateTimeRemaining($stats, $processingRate);
// Check if process is actually active (processed something in last 2 minutes)
$recentActivity = checkRecentActivity($db);
echo json_encode([
'success' => true,
'is_running' => $state ? (bool)$state['is_running'] : false,
'should_pause' => $state ? (bool)$state['should_pause'] : false,
'stats' => $stats,
'processing_rate' => $processingRate,
'time_remaining' => $timeRemaining,
'recent_activity' => $recentActivity,
'started_at' => $state ? $state['started_at'] : null,
'last_updated' => $state ? $state['last_updated'] : null
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
function getCurrentStats($db) {
$stats = [];
// Total combinations
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$stats['total'] = $totalQuery ? $totalQuery->fetch_assoc()['count'] : 0;
// Processed combinations
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$stats['processed'] = $processedQuery ? $processedQuery->fetch_assoc()['count'] : 0;
// Possible combinations
$possibleQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 0");
$stats['possible'] = $possibleQuery ? $possibleQuery->fetch_assoc()['count'] : 0;
// Impossible combinations
$impossibleQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1");
$stats['impossible'] = $impossibleQuery ? $impossibleQuery->fetch_assoc()['count'] : 0;
// Pending combinations
$stats['pending'] = $stats['total'] - $stats['processed'];
// Progress percentage
$stats['progress'] = $stats['total'] > 0 ? ($stats['processed'] / $stats['total']) * 100 : 0;
return $stats;
}
function calculateProcessingRate($db) {
try {
// Get combinations processed in the last 5 minutes
$query = $db->query("
SELECT COUNT(*) as count
FROM panel_directives
WHERE llm_checked = 1
AND updated_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
");
$recentCount = $query ? $query->fetch_assoc()['count'] : 0;
// Calculate rate per minute (combinations in 5 minutes / 5)
$ratePerMinute = $recentCount / 5;
return round($ratePerMinute, 2);
} catch (Exception $e) {
return 0;
}
}
function estimateTimeRemaining($stats, $processingRate) {
if ($processingRate <= 0 || $stats['pending'] <= 0) {
return null;
}
$minutesRemaining = $stats['pending'] / $processingRate;
if ($minutesRemaining < 60) {
return round($minutesRemaining) . ' minutes';
} elseif ($minutesRemaining < 1440) { // Less than 24 hours
$hours = floor($minutesRemaining / 60);
$minutes = round($minutesRemaining % 60);
return $hours . 'h ' . $minutes . 'm';
} else {
$days = floor($minutesRemaining / 1440);
$hours = floor(($minutesRemaining % 1440) / 60);
return $days . 'd ' . $hours . 'h';
}
}
function checkRecentActivity($db) {
try {
// Check for combinations processed in last 2 minutes
$query = $db->query("
SELECT COUNT(*) as count
FROM panel_directives
WHERE llm_checked = 1
AND updated_at > DATE_SUB(NOW(), INTERVAL 2 MINUTE)
");
$recentCount = $query ? $query->fetch_assoc()['count'] : 0;
return [
'has_activity' => $recentCount > 0,
'recent_count' => $recentCount,
'last_activity' => getLastActivity($db)
];
} catch (Exception $e) {
return [
'has_activity' => false,
'recent_count' => 0,
'last_activity' => null
];
}
}
function getLastActivity($db) {
try {
$query = $db->query("
SELECT MAX(updated_at) as last_update
FROM panel_directives
WHERE llm_checked = 1
");
$result = $query ? $query->fetch_assoc() : null;
return $result ? $result['last_update'] : null;
} catch (Exception $e) {
return null;
}
}
?>
-------------------- END OF FILE --------------------
### FILE 22: syndia.kreahealthcare.com/enhanced_process_optimization.php
- Type: PHP
- Size: 12.56 KB
- Path: syndia.kreahealthcare.com
- Name: enhanced_process_optimization.php
------------------------------------------------------------
0 ? ($processed / $total) * 100 : 0;
writeLog(sprintf("Progress: %d/%d (%.1f%%) | Rate: %.1f/min | ETA: %s",
$processed, $total, $progress, $rate, $eta));
}
try {
writeLog("=== Enhanced OptimAIze Analysis Started ===");
writeLog("Batch Size: " . BATCH_SIZE);
writeLog("Parallel Requests: " . PARALLEL_REQUESTS);
writeLog("Rate Limit Delay: " . RATE_LIMIT_DELAY . " seconds");
$db = Database::getInstance();
writeLog("✅ Database connected");
// Reset GPT rate limits for faster processing
GptHelper::resetRateLimit();
writeLog("✅ GPT rate limits reset");
$startTime = microtime(true);
$batchCount = 0;
$totalProcessed = 0;
$successCount = 0;
$errorCount = 0;
while (true) {
// Check if analysis should pause or stop
$stateQuery = $db->query("SELECT is_running, should_pause FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
if (!$state || !$state['is_running']) {
writeLog("❌ Analysis not running - stopping");
break;
}
if ($state['should_pause']) {
writeLog("⏸️ Pause requested - stopping gracefully");
break;
}
$batchCount++;
$batchStartTime = microtime(true);
// Get next batch of unprocessed combinations
$query = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2,
attribute1_name, attribute2_name
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT " . BATCH_SIZE
);
if (!$query || $query->num_rows == 0) {
writeLog("🎉 No more combinations to process - analysis complete!");
// Mark analysis as completed
$db->query("UPDATE optimization_analysis_state SET
is_running = 0,
completed_at = NOW()
WHERE is_running = 1");
break;
}
$combinations = [];
while ($row = $query->fetch_assoc()) {
$combinations[] = $row;
}
writeLog("📦 Batch #$batchCount: Processing " . count($combinations) . " combinations");
// Process combinations in parallel groups
$batchResults = processCombinationsInParallel($combinations, $db);
$batchSuccessCount = 0;
$batchErrorCount = 0;
foreach ($batchResults as $result) {
if ($result['success']) {
$batchSuccessCount++;
$successCount++;
} else {
$batchErrorCount++;
$errorCount++;
}
}
$totalProcessed += count($combinations);
$batchTime = microtime(true) - $batchStartTime;
$batchRate = count($combinations) / ($batchTime / 60); // per minute
writeLog("✅ Batch completed: {$batchSuccessCount} success, {$batchErrorCount} errors, {$batchRate:.1f} combinations/min");
// Update progress in database every few batches
if ($batchCount % STATUS_UPDATE_INTERVAL == 0) {
updateProgress($db, $totalProcessed);
// Calculate overall statistics
$totalTime = microtime(true) - $startTime;
$overallRate = $totalProcessed / ($totalTime / 60);
$remainingQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 0");
$remaining = $remainingQuery ? $remainingQuery->fetch_assoc()['count'] : 0;
$eta = $remaining > 0 && $overallRate > 0 ? gmdate("H:i:s", ($remaining / $overallRate) * 60) : "Unknown";
writeProgressLog($totalProcessed, $totalProcessed + $remaining, $overallRate, $eta);
}
// Brief delay to prevent overwhelming the API
if (RATE_LIMIT_DELAY > 0) {
sleep(RATE_LIMIT_DELAY);
}
}
// Final statistics
$totalTime = microtime(true) - $startTime;
$overallRate = $totalProcessed / ($totalTime / 60);
writeLog("=== Analysis Complete ===");
writeLog("Total Processed: $totalProcessed");
writeLog("Success: $successCount");
writeLog("Errors: $errorCount");
writeLog("Total Time: " . gmdate("H:i:s", $totalTime));
writeLog("Average Rate: {$overallRate:.1f} combinations/minute");
// Final progress update
updateProgress($db, $totalProcessed);
} catch (Exception $e) {
writeLog("❌ Fatal Error: " . $e->getMessage());
writeLog("Stack trace: " . $e->getTraceAsString());
// Mark analysis as stopped due to error
if (isset($db)) {
$db->query("UPDATE optimization_analysis_state SET
is_running = 0,
completed_at = NOW()
WHERE is_running = 1");
}
}
/**
* Process combinations in parallel for maximum speed
*/
function processCombinationsInParallel($combinations, $db) {
$results = [];
$chunks = array_chunk($combinations, PARALLEL_REQUESTS);
foreach ($chunks as $chunk) {
$chunkResults = processChunkInParallel($chunk, $db);
$results = array_merge($results, $chunkResults);
}
return $results;
}
/**
* Process a small chunk of combinations in parallel
*/
function processChunkInParallel($combinations, $db) {
$results = [];
$curlHandles = [];
$multiHandle = curl_multi_init();
// Prepare all requests
foreach ($combinations as $index => $combination) {
$prompt = buildAnalysisPrompt($combination);
$curlHandle = createGptCurlRequest($prompt);
if ($curlHandle) {
$curlHandles[$index] = [
'handle' => $curlHandle,
'combination' => $combination
];
curl_multi_add_handle($multiHandle, $curlHandle);
}
}
// Execute all requests in parallel
$running = null;
do {
curl_multi_exec($multiHandle, $running);
curl_multi_select($multiHandle);
} while ($running > 0);
// Process results
foreach ($curlHandles as $index => $data) {
$response = curl_multi_getcontent($data['handle']);
$httpCode = curl_getinfo($data['handle'], CURLINFO_HTTP_CODE);
$result = processGptResponse($response, $httpCode, $data['combination'], $db);
$results[] = $result;
curl_multi_remove_handle($multiHandle, $data['handle']);
curl_close($data['handle']);
}
curl_multi_close($multiHandle);
return $results;
}
/**
* Create a cURL handle for GPT API request
*/
function createGptCurlRequest($prompt) {
$data = [
'model' => 'gpt-4',
'messages' => [
[
'role' => 'system',
'content' => 'You are an expert demographic analyst. Analyze if the given combination of demographic attributes is logically possible or impossible in real-world scenarios. Respond with either "POSSIBLE" or "IMPOSSIBLE" followed by a brief reason.'
],
[
'role' => 'user',
'content' => $prompt
]
],
'max_tokens' => 150,
'temperature' => 0.1
];
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . OPENAI_API_KEY,
'Content-Type: application/json'
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1
]);
return $ch;
}
/**
* Build analysis prompt for a combination
*/
function buildAnalysisPrompt($combination) {
return sprintf(
"Analyze this demographic combination:\n\n%s = %s\n%s = %s\n\nIs this combination logically possible in real-world demographics? Consider biological, legal, social, and logical constraints.",
$combination['attribute1_name'],
$combination['choice1'],
$combination['attribute2_name'],
$combination['choice2']
);
}
/**
* Process GPT API response and update database
*/
function processGptResponse($response, $httpCode, $combination, $db) {
try {
if ($httpCode !== 200) {
throw new Exception("HTTP Error: $httpCode");
}
$data = json_decode($response, true);
if (!$data || !isset($data['choices'][0]['message']['content'])) {
throw new Exception("Invalid response format");
}
$content = trim($data['choices'][0]['message']['content']);
$isImpossible = stripos($content, 'IMPOSSIBLE') === 0 ? 1 : 0;
// Extract reasoning (everything after POSSIBLE/IMPOSSIBLE)
$reasoning = trim(str_ireplace(['POSSIBLE', 'IMPOSSIBLE'], '', $content));
if (empty($reasoning)) {
$reasoning = $content;
}
// Update database
$stmt = $db->prepare("UPDATE panel_directives SET
llm_checked = 1,
is_impossible = ?,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?");
$stmt->bind_param('isi', $isImpossible, $reasoning, $combination['id']);
if (!$stmt->execute()) {
throw new Exception("Database update failed");
}
return [
'success' => true,
'combination_id' => $combination['id'],
'is_impossible' => $isImpossible,
'reasoning' => $reasoning
];
} catch (Exception $e) {
// Mark as checked but with error
$stmt = $db->prepare("UPDATE panel_directives SET
llm_checked = 1,
is_impossible = 0,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?");
$errorMsg = "Error: " . $e->getMessage();
$stmt->bind_param('si', $errorMsg, $combination['id']);
$stmt->execute();
return [
'success' => false,
'combination_id' => $combination['id'],
'error' => $e->getMessage()
];
}
}
/**
* Update progress in database
*/
function updateProgress($db, $processed) {
try {
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
processed_combinations = ?,
last_updated = NOW()
WHERE is_running = 1");
$stmt->bind_param('i', $processed);
$stmt->execute();
} catch (Exception $e) {
writeLog("Warning: Could not update progress: " . $e->getMessage());
}
}
?>
-------------------- END OF FILE --------------------
### FILE 23: syndia.kreahealthcare.com/error_log
- Type:
- Size: 0 B
- Path: syndia.kreahealthcare.com
- Name: error_log
------------------------------------------------------------
[BINARY/UNKNOWN FILE: - Content not displayed]
-------------------- END OF FILE --------------------
### FILE 24: syndia.kreahealthcare.com/export_attributes.php
- Type: PHP
- Size: 1.4 KB
- Path: syndia.kreahealthcare.com
- Name: export_attributes.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized access');
}
$db = Database::getInstance();
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="attributes_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Write headers
$headers = ['ID', 'Attribute Name', 'Choice Type', 'Choices', 'Created By', 'Created Date'];
fputcsv($output, $headers);
// Get all attributes with creator info
$query = $db->query("
SELECT a.*, u.full_name as creator_name, DATE_FORMAT(a.created_at, '%Y-%m-%d %H:%i:%S') as formatted_date
FROM attributes a
LEFT JOIN users u ON a.created_by = u.id
ORDER BY a.created_at ASC
");
// Write data rows
while ($attr = $query->fetch_assoc()) {
$choices = json_decode($attr['choices'], true);
$choicesText = implode(', ', $choices);
$row = [
$attr['id'],
$attr['name'],
$attr['choice_type'],
$choicesText,
$attr['creator_name'],
$attr['formatted_date']
];
fputcsv($output, $row);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 25: syndia.kreahealthcare.com/export_panel.php
- Type: PHP
- Size: 1.6 KB
- Path: syndia.kreahealthcare.com
- Name: export_panel.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized access');
}
$db = Database::getInstance();
// Get all attributes for headers
$attributes = $db->query("
SELECT id, name
FROM attributes
ORDER BY created_at ASC
");
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="panel_data_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Write headers
$headers = ['Panelist ID'];
while ($attr = $attributes->fetch_assoc()) {
$headers[] = $attr['name'];
}
fputcsv($output, $headers);
// Get all panel data
$panel_query = $db->query("
SELECT *
FROM panel_data
ORDER BY created_at ASC
");
// Write data rows
while ($panel = $panel_query->fetch_assoc()) {
$row = [str_pad($panel['panelist_id'], 6, '0', STR_PAD_LEFT)];
$attributes->data_seek(0); // Reset attributes pointer
$values = json_decode($panel['attribute_values'], true);
while ($attr = $attributes->fetch_assoc()) {
$value = $values[$attr['id']] ?? '-';
// Handle array values for multiple-choice attributes
if (is_array($value)) {
$value = implode(', ', $value);
}
$row[] = $value;
}
fputcsv($output, $row);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 26: syndia.kreahealthcare.com/export_project_data.php
- Type: PHP
- Size: 4.98 KB
- Path: syndia.kreahealthcare.com
- Name: export_project_data.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized');
}
$db = Database::getInstance();
// Get project ID from URL
$project_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$project_id) {
die('Invalid project ID');
}
// Verify user has access to this project
$stmt = $db->prepare("SELECT id, title FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
$project = $stmt->get_result()->fetch_assoc();
if (!$project) {
die('Project not found or access denied');
}
// Get all selections for this project
$stmt = $db->prepare("SELECT id, name FROM selections WHERE project_id = ? ORDER BY created_at ASC");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$selections_result = $stmt->get_result();
$selections = [];
while ($row = $selections_result->fetch_assoc()) {
$selections[] = $row;
}
if (empty($selections)) {
die('No selections found for this project');
}
// Get connected survey
$stmt = $db->prepare("
SELECT s.id as survey_id, s.title as survey_title
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = ?
LIMIT 1
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$connected_survey = $stmt->get_result()->fetch_assoc();
if (!$connected_survey) {
die('No survey connected to this project');
}
// Get survey questions
$stmt = $db->prepare("
SELECT id, question_text, question_type
FROM survey_questions
WHERE survey_id = ? AND question_type NOT IN ('section_header', 'descriptive_text', 'page_break')
ORDER BY question_order ASC
");
$stmt->bind_param('i', $connected_survey['survey_id']);
$stmt->execute();
$questions_result = $stmt->get_result();
$questions = [];
while ($question = $questions_result->fetch_assoc()) {
$questions[] = $question;
}
// Get all attributes
$attributes = [];
$attr_query = $db->query("SELECT id, name FROM attributes ORDER BY created_at ASC");
while ($attr = $attr_query->fetch_assoc()) {
$attributes[$attr['id']] = $attr['name'];
}
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="project_' . $project_id . '_data_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Prepare headers
$headers = ['Selection Name', 'Panelist ID'];
// Add attribute headers
foreach ($attributes as $attr_name) {
$headers[] = 'Attr_' . $attr_name;
}
// Add question headers
foreach ($questions as $question) {
$headers[] = 'Q' . $question['id'] . '_' . substr(preg_replace('/\s+/', '_', $question['question_text']), 0, 30);
}
// Write headers
fputcsv($output, $headers);
// Process each selection and its members
foreach ($selections as $selection) {
// Get members with their attributes
$stmt = $db->prepare("
SELECT sm.panelist_id, pd.attribute_values
FROM selection_members sm
LEFT JOIN panel_data pd ON sm.panelist_id = pd.panelist_id
WHERE sm.selection_id = ?
ORDER BY sm.id ASC
");
$stmt->bind_param('i', $selection['id']);
$stmt->execute();
$members_result = $stmt->get_result();
while ($member = $members_result->fetch_assoc()) {
$row = [$selection['name'], $member['panelist_id']];
// Get member attributes
$attribute_values = json_decode($member['attribute_values'], true);
// Add attribute values
foreach ($attributes as $attr_id => $attr_name) {
if (isset($attribute_values[$attr_id])) {
// Handle array attributes (multiple choice)
if (is_array($attribute_values[$attr_id])) {
$row[] = implode(", ", $attribute_values[$attr_id]);
} else {
$row[] = $attribute_values[$attr_id];
}
} else {
$row[] = '';
}
}
// Get responses for this member
$stmt = $db->prepare("
SELECT question_id, response_text
FROM synthetic_responses
WHERE selection_id = ? AND panelist_id = ?
");
$stmt->bind_param('is', $selection['id'], $member['panelist_id']);
$stmt->execute();
$responses_result = $stmt->get_result();
$responses = [];
while ($response = $responses_result->fetch_assoc()) {
$responses[$response['question_id']] = $response['response_text'];
}
// Add response values
foreach ($questions as $question) {
$row[] = isset($responses[$question['id']]) ? $responses[$question['id']] : '';
}
// Write the row
fputcsv($output, $row);
}
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 27: syndia.kreahealthcare.com/export_raw_data.php
- Type: PHP
- Size: 4.56 KB
- Path: syndia.kreahealthcare.com
- Name: export_raw_data.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized');
}
$db = Database::getInstance();
// Get selection ID from URL
$selection_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$selection_id) {
die('Invalid selection ID');
}
// Verify user has access to this selection
$stmt = $db->prepare("
SELECT s.*, p.id as project_id, p.title as project_title
FROM selections s
JOIN projects p ON s.project_id = p.id
WHERE s.id = ? AND p.created_by = ?
");
$stmt->bind_param('ii', $selection_id, $_SESSION['user_id']);
$stmt->execute();
$selection = $stmt->get_result()->fetch_assoc();
if (!$selection) {
die('Selection not found or access denied');
}
// Get project's connected survey
$stmt = $db->prepare("
SELECT s.id as survey_id, s.title as survey_title
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = ?
LIMIT 1
");
$stmt->bind_param('i', $selection['project_id']);
$stmt->execute();
$connected_survey = $stmt->get_result()->fetch_assoc();
if (!$connected_survey) {
die('No survey connected to this project');
}
// Get survey questions
$stmt = $db->prepare("
SELECT id, question_text, question_type
FROM survey_questions
WHERE survey_id = ? AND question_type NOT IN ('section_header', 'descriptive_text', 'page_break')
ORDER BY question_order ASC
");
$stmt->bind_param('i', $connected_survey['survey_id']);
$stmt->execute();
$questions_result = $stmt->get_result();
$questions = [];
while ($question = $questions_result->fetch_assoc()) {
$questions[] = $question;
}
// Get all attributes
$attributes = [];
$attr_query = $db->query("SELECT id, name FROM attributes ORDER BY created_at ASC");
while ($attr = $attr_query->fetch_assoc()) {
$attributes[$attr['id']] = $attr['name'];
}
// Get members with their attributes and responses
$stmt = $db->prepare("
SELECT sm.panelist_id, pd.attribute_values
FROM selection_members sm
LEFT JOIN panel_data pd ON sm.panelist_id = pd.panelist_id
WHERE sm.selection_id = ?
ORDER BY sm.id ASC
");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$members_result = $stmt->get_result();
$members = [];
while ($member = $members_result->fetch_assoc()) {
$members[$member['panelist_id']] = [
'attributes' => json_decode($member['attribute_values'], true),
'responses' => []
];
}
// Get all responses for this selection
$stmt = $db->prepare("
SELECT sr.panelist_id, sr.question_id, sr.response_text
FROM synthetic_responses sr
WHERE sr.selection_id = ?
");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$responses_result = $stmt->get_result();
// Organize responses by panelist
while ($response = $responses_result->fetch_assoc()) {
if (isset($members[$response['panelist_id']])) {
$members[$response['panelist_id']]['responses'][$response['question_id']] = $response['response_text'];
}
}
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="selection_' . $selection_id . '_raw_data_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Prepare headers
$headers = ['Panelist ID'];
// Add attribute headers
foreach ($attributes as $attr_name) {
$headers[] = 'Attr_' . $attr_name;
}
// Add question headers
foreach ($questions as $question) {
$headers[] = 'Q' . $question['id'] . '_' . substr(preg_replace('/\s+/', '_', $question['question_text']), 0, 30);
}
// Write headers
fputcsv($output, $headers);
// Write data rows
foreach ($members as $panelist_id => $data) {
$row = [$panelist_id];
// Add attribute values
foreach ($attributes as $attr_id => $attr_name) {
if (isset($data['attributes'][$attr_id])) {
// Handle array attributes (multiple choice)
if (is_array($data['attributes'][$attr_id])) {
$row[] = implode(", ", $data['attributes'][$attr_id]);
} else {
$row[] = $data['attributes'][$attr_id];
}
} else {
$row[] = '';
}
}
// Add response values
foreach ($questions as $question) {
$row[] = isset($data['responses'][$question['id']]) ? $data['responses'][$question['id']] : '';
}
fputcsv($output, $row);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 28: syndia.kreahealthcare.com/export_selection.php
- Type: PHP
- Size: 2.28 KB
- Path: syndia.kreahealthcare.com
- Name: export_selection.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized');
}
$db = Database::getInstance();
// Get selection ID from URL
$selection_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$selection_id) {
die('Invalid selection ID');
}
// Get selection details
$stmt = $db->prepare("
SELECT s.*, p.project_id as project_code, p.title as project_title
FROM selections s
JOIN projects p ON s.project_id = p.id
WHERE s.id = ? AND p.created_by = ?
");
$stmt->bind_param('ii', $selection_id, $_SESSION['user_id']);
$stmt->execute();
$selection = $stmt->get_result()->fetch_assoc();
if (!$selection) {
die('Selection not found or access denied');
}
// Get selection members
$stmt = $db->prepare("
SELECT sm.panelist_id, pd.attribute_values
FROM selection_members sm
LEFT JOIN panel_data pd ON sm.panelist_id = pd.panelist_id
WHERE sm.selection_id = ?
ORDER BY sm.id ASC
");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$members_result = $stmt->get_result();
// Get all attributes
$attributes = [];
$attr_query = $db->query("SELECT id, name FROM attributes ORDER BY created_at ASC");
while ($attr = $attr_query->fetch_assoc()) {
$attributes[$attr['id']] = $attr['name'];
}
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="selection_' . $selection_id . '_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Write headers
$headers = ['#', 'Panelist ID'];
foreach ($attributes as $attr_name) {
$headers[] = $attr_name;
}
fputcsv($output, $headers);
// Write data rows
$counter = 1;
while ($member = $members_result->fetch_assoc()) {
$row = [$counter++, $member['panelist_id']];
$attribute_values = json_decode($member['attribute_values'], true);
foreach ($attributes as $attr_id => $attr_name) {
$row[] = isset($attribute_values[$attr_id]) ? $attribute_values[$attr_id] : '';
}
fputcsv($output, $row);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 29: syndia.kreahealthcare.com/export_statistics_check.php
- Type: PHP
- Size: 1.82 KB
- Path: syndia.kreahealthcare.com
- Name: export_statistics_check.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized access');
}
$db = Database::getInstance();
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="statistic_check_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Write headers
$headers = ['Statistic Name', 'Combination', 'Target %', 'Panel %', 'Deviation %'];
fputcsv($output, $headers);
// Get all combinations data
$query = $db->query("
SELECT
s.name as statistic_name,
sc.combination_values,
sc.percentage as target_percentage,
sc.actual_percentage as panel_percentage
FROM statistics s
JOIN statistic_combinations sc ON s.id = sc.statistic_id
ORDER BY s.name, sc.id
");
// Write data rows
while ($row = $query->fetch_assoc()) {
$target_percentage = floatval($row['target_percentage']);
$panel_percentage = floatval($row['panel_percentage'] ?? 0);
// Calculate deviation percentage
$deviation = $target_percentage > 0 ?
(($panel_percentage - $target_percentage) / $target_percentage) * 100 :
0;
// Format the combination
$values = json_decode($row['combination_values'], true);
$combination = implode(' × ', $values);
$csvRow = [
$row['statistic_name'],
$combination,
number_format($target_percentage, 2),
number_format($panel_percentage, 2),
number_format($deviation, 2)
];
fputcsv($output, $csvRow);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 30: syndia.kreahealthcare.com/export_statistics.php
- Type: PHP
- Size: 2.27 KB
- Path: syndia.kreahealthcare.com
- Name: export_statistics.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized access');
}
$db = Database::getInstance();
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="statistics_' . date('Y-m-d') . '.csv"');
// Create output stream
$output = fopen('php://output', 'w');
// Add BOM for Excel UTF-8 compatibility
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Write headers
$headers = ['Statistic Name', 'Type', 'Attributes', 'Combination', 'Target %', 'Panel %', 'Deviation %', 'Created By', 'Created Date'];
fputcsv($output, $headers);
// Get statistics data with combinations
$query = $db->query("
SELECT
s.name as statistic_name,
s.type,
u.full_name as creator_name,
DATE_FORMAT(s.created_at, '%Y-%m-%d %H:%i:%S') as formatted_date,
GROUP_CONCAT(DISTINCT a.name ORDER BY sa.id) as attribute_names,
sc.combination_values,
sc.percentage as target_percentage,
sc.actual_percentage
FROM statistics s
LEFT JOIN users u ON s.created_by = u.id
JOIN statistic_attributes sa ON s.id = sa.statistic_id
JOIN attributes a ON a.id = sa.attribute_id
JOIN statistic_combinations sc ON s.id = sc.statistic_id
GROUP BY s.id, sc.id
ORDER BY s.name, sc.id
");
// Write data rows
while ($stat = $query->fetch_assoc()) {
$targetPct = floatval($stat['target_percentage']);
$actualPct = floatval($stat['actual_percentage'] ?? 0);
$deviation = $targetPct > 0 ? (($actualPct - $targetPct) / $targetPct) * 100 : 0;
// Format the combination values
$combinationValues = json_decode($stat['combination_values'], true);
$combinationText = implode(' × ', $combinationValues);
$row = [
$stat['statistic_name'],
$stat['type'],
$stat['attribute_names'],
$combinationText,
number_format($targetPct, 2),
number_format($actualPct, 2),
number_format($deviation, 2),
$stat['creator_name'],
$stat['formatted_date']
];
fputcsv($output, $row);
}
fclose($output);
exit;
-------------------- END OF FILE --------------------
### FILE 31: syndia.kreahealthcare.com/file_check.php
- Type: PHP
- Size: 1.54 KB
- Path: syndia.kreahealthcare.com
- Name: file_check.php
------------------------------------------------------------
File System Check";
echo "Current directory: " . __DIR__ . "
";
// List all files in the current directory
echo "Files in current directory: ";
$files = scandir(__DIR__);
echo "";
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
echo "" . htmlspecialchars($file) . " - " . (file_exists(__DIR__ . '/' . $file) ? 'exists' : 'not found') . " ";
}
}
echo " ";
// Check specific files
$requiredFiles = [
'get_survey_questions.php',
'save_survey_question.php',
'delete_survey_question.php',
'move_survey_question.php',
'update_question_order.php'
];
echo "Required files check: ";
echo "";
foreach ($requiredFiles as $file) {
$exists = file_exists(__DIR__ . '/' . $file);
echo "" . htmlspecialchars($file) . " - " . ($exists ? 'exists' : 'not found') . " ";
if ($exists) {
// Check permissions
$perms = fileperms(__DIR__ . '/' . $file);
$permsStr = sprintf('%o', $perms);
echo " - Permissions: " . $permsStr;
}
}
echo " ";
// Check if we can include the file
echo "Testing include: ";
foreach ($requiredFiles as $file) {
echo "Testing include of " . htmlspecialchars($file) . ": ";
try {
if (file_exists(__DIR__ . '/' . $file)) {
include_once(__DIR__ . '/' . $file);
echo "success";
} else {
echo "file not found";
}
} catch (Exception $e) {
echo "error: " . $e->getMessage();
}
echo "
";
}
?>
-------------------- END OF FILE --------------------
### FILE 32: syndia.kreahealthcare.com/fix_optimaize.php
- Type: PHP
- Size: 12.18 KB
- Path: syndia.kreahealthcare.com
- Name: fix_optimaize.php
------------------------------------------------------------
isLoggedIn() || !$auth->isAdmin()) {
die("Admin access required");
}
header('Content-Type: text/html; charset=utf-8');
echo "OptimAIze Fix & Test Script ";
echo "";
$db = Database::getInstance();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$action = $_POST['action'] ?? '';
switch ($action) {
case 'test_gpt':
echo "Testing GPT Connection ";
testGPTConnection();
break;
case 'reset_analysis':
echo "Resetting Analysis State ";
resetAnalysisState();
break;
case 'start_analysis':
echo "Starting Analysis ";
startAnalysis();
break;
case 'check_background':
echo "Checking Background Process ";
checkBackgroundProcess();
break;
}
}
echo "Current Status ";
displayCurrentStatus();
echo "Available Actions ";
echo "";
echo "1. Test GPT Connection ";
echo "2. Reset Analysis State ";
echo "3. Start Analysis ";
echo "4. Check Background Process ";
echo " ";
echo "";
echo "
Recommended Steps: ";
echo "
";
echo "Test GPT Connection - Verify GPT API is working ";
echo "Reset Analysis State - Clear stuck state ";
echo "Start Analysis - Begin processing combinations ";
echo "Check Background Process - Monitor progress ";
echo " ";
echo "
";
function displayCurrentStatus() {
global $db;
// Check GptHelper class
try {
require_once 'includes/GptHelper.php';
if (class_exists('GptHelper')) {
echo "✅ GptHelper class loaded successfully
";
} else {
echo "❌ GptHelper class not found
";
}
} catch (Exception $e) {
echo "❌ Error loading GptHelper: " . $e->getMessage() . "
";
}
// Check analysis state
$stateResult = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
if ($stateResult && $stateResult->num_rows > 0) {
$state = $stateResult->fetch_assoc();
$statusClass = $state['is_running'] ? 'warning' : 'info';
$statusText = $state['is_running'] ? 'RUNNING' : 'STOPPED';
echo "Analysis Status: $statusText
";
echo "Progress: " . number_format($state['processed_combinations']) . " / " . number_format($state['total_combinations']) . " combinations
";
}
// Check recent progress
$recentCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND updated_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)")->fetch_assoc()['count'];
if ($recentCount > 0) {
echo "✅ Recent activity: $recentCount combinations processed in last 5 minutes
";
} else {
echo "⚠️ No recent activity detected
";
}
}
function testGPTConnection() {
try {
require_once 'includes/GptHelper.php';
if (!class_exists('GptHelper')) {
throw new Exception("GptHelper class not found");
}
echo "✅ GptHelper class loaded
";
// Test simple GPT request
$testMessages = [
[
'role' => 'user',
'content' => 'Respond with exactly: "TEST SUCCESSFUL"'
]
];
echo "📡 Sending test request to OpenAI...
";
$response = GptHelper::makeRequest($testMessages, 'gpt-4', 0.3);
if ($response['success']) {
echo "✅ GPT connection successful!
";
echo "Response: " . htmlspecialchars($response['response']) . "
";
// Test the specific analysis function
echo "🔍 Testing demographic analysis...
";
$analysisResult = GptHelper::analyzeCombination('Age', '5-12 years', 'Marital Status', 'Married');
if ($analysisResult['is_impossible']) {
echo "✅ Analysis function working correctly (correctly identified impossible combination)
";
} else {
echo "⚠️ Analysis function working but may need tuning
";
}
echo "Analysis result: " . htmlspecialchars($analysisResult['reasoning']) . "
";
} else {
echo "❌ GPT connection failed: " . htmlspecialchars($response['error']) . "
";
}
} catch (Exception $e) {
echo "❌ Error testing GPT: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function resetAnalysisState() {
global $db;
try {
// Stop any running analysis
$db->query("UPDATE optimization_analysis_state SET is_running = 0, completed_at = NULL WHERE id > 0");
echo "✅ Analysis state reset to stopped
";
// Reset processed count
$db->query("UPDATE optimization_analysis_state SET processed_combinations = 0 WHERE id > 0");
echo "✅ Progress counter reset
";
// Optionally reset all directives (uncomment if you want to start completely fresh)
// $db->query("UPDATE panel_directives SET llm_checked = 0, is_impossible = 0, llm_reasoning = NULL, status = 'pending' WHERE id > 0");
// echo "✅ All directives reset to unchecked state
";
echo "ℹ️ Analysis state has been reset. You can now start a fresh analysis.
";
} catch (Exception $e) {
echo "❌ Error resetting analysis: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function startAnalysis() {
global $db;
try {
// Check if already running
$stateResult = $db->query("SELECT is_running FROM optimization_analysis_state WHERE is_running = 1 LIMIT 1");
if ($stateResult && $stateResult->num_rows > 0) {
echo "⚠️ Analysis is already running
";
return;
}
// Get total combinations
$totalResult = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalResult->fetch_assoc()['count'];
if ($totalCombinations == 0) {
echo "❌ No combinations found. Generate combinations first.
";
return;
}
// Mark as running
$stmt = $db->prepare("UPDATE optimization_analysis_state SET is_running = 1, started_at = NOW(), total_combinations = ? WHERE id = (SELECT id FROM optimization_analysis_state ORDER BY id DESC LIMIT 1)");
$stmt->bind_param('i', $totalCombinations);
$stmt->execute();
echo "✅ Analysis marked as running
";
echo "📊 Total combinations: " . number_format($totalCombinations) . "
";
// Start background process
$command = "php " . __DIR__ . "/process_optimization_analysis.php > /dev/null 2>&1 &";
exec($command);
echo "✅ Background process started
";
echo "ℹ️ The analysis will run in the background. Check progress in the OptimAIze page.
";
// Wait a moment and check if it started
sleep(3);
$logFile = __DIR__ . '/optimization_analysis.log';
if (file_exists($logFile)) {
$logContent = file_get_contents($logFile);
$recentEntries = substr($logContent, -1000); // Last 1000 characters
echo "📝 Recent log entries:
";
echo "" . htmlspecialchars($recentEntries) . " ";
}
} catch (Exception $e) {
echo "❌ Error starting analysis: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function checkBackgroundProcess() {
global $db;
// Check if marked as running
$stateResult = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateResult ? $stateResult->fetch_assoc() : null;
if ($state) {
$statusClass = $state['is_running'] ? 'success' : 'info';
$statusText = $state['is_running'] ? 'RUNNING' : 'STOPPED';
echo "Process Status: $statusText
";
if ($state['is_running']) {
$progress = $state['total_combinations'] > 0 ? ($state['processed_combinations'] / $state['total_combinations']) * 100 : 0;
echo "📊 Progress: " . number_format($progress, 2) . "%
";
// Check recent activity
$recentCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND updated_at > DATE_SUB(NOW(), INTERVAL 2 MINUTE)")->fetch_assoc()['count'];
if ($recentCount > 0) {
echo "✅ Active: $recentCount combinations processed in last 2 minutes
";
} else {
echo "⚠️ No recent activity - process may be stuck
";
}
}
}
// Check log file
$logFile = __DIR__ . '/optimization_analysis.log';
if (file_exists($logFile)) {
$fileSize = filesize($logFile);
$lastModified = date('Y-m-d H:i:s', filemtime($logFile));
echo "📝 Log file: " . number_format($fileSize) . " bytes, last modified: $lastModified
";
// Show recent log entries
$logContent = file_get_contents($logFile);
$logLines = explode("\n", $logContent);
$recentLines = array_slice($logLines, -10); // Last 10 lines
echo "Recent log entries:
";
echo "";
foreach ($recentLines as $line) {
if (trim($line)) {
echo htmlspecialchars($line) . "\n";
}
}
echo " ";
} else {
echo "⚠️ Log file not found - background process may not be running
";
}
}
?>
-------------------- END OF FILE --------------------
### FILE 33: syndia.kreahealthcare.com/fix_stuck_analysis.php
- Type: PHP
- Size: 22.95 KB
- Path: syndia.kreahealthcare.com
- Name: fix_stuck_analysis.php
------------------------------------------------------------
🔧 Fix Stuck Analysis";
echo "";
try {
$auth = new Auth();
if (!$auth->isLoggedIn()) {
die("❌ Please log in first
");
}
$db = Database::getInstance();
// Get action parameter
$action = $_GET['action'] ?? '';
if ($action) {
handleAction($action, $db);
} else {
diagnoseIssue($db);
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
function diagnoseIssue($db) {
echo "";
echo "
🔍 Diagnosing Stuck Analysis ";
// Check current state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
if ($state) {
echo "
Analysis marked as running: " . ($state['is_running'] ? '✅ Yes' : '❌ No') . "
";
echo "
Should pause: " . ($state['should_pause'] ? '⚠️ Yes' : '✅ No') . "
";
echo "
Started at: " . ($state['started_at'] ?? 'Never') . "
";
echo "
Last updated: " . ($state['last_updated'] ?? 'Never') . "
";
}
// Check recent activity
$recentQuery = $db->query("
SELECT COUNT(*) as count, MAX(updated_at) as last_update
FROM panel_directives
WHERE llm_checked = 1
AND updated_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE)
");
$recent = $recentQuery->fetch_assoc();
echo "
Recent activity (10 min): " . $recent['count'] . " combinations
";
echo "
Last activity: " . ($recent['last_update'] ?? 'None') . "
";
// Check total progress
$progressQuery = $db->query("
SELECT
COUNT(*) as total,
SUM(llm_checked) as processed,
SUM(CASE WHEN llm_checked = 1 AND is_impossible = 1 THEN 1 ELSE 0 END) as impossible
FROM panel_directives
");
$progress = $progressQuery->fetch_assoc();
echo "
Total progress: {$progress['processed']} / {$progress['total']} combinations
";
echo "
Impossible found: {$progress['impossible']}
";
echo "
";
// Check log files
echo "";
echo "
📋 Log File Analysis ";
$logFiles = [
'optimization_analysis.log',
'enhanced_optimization.log',
'error_log'
];
foreach ($logFiles as $logFile) {
if (file_exists($logFile)) {
$size = filesize($logFile);
$modified = date('Y-m-d H:i:s', filemtime($logFile));
echo "
✅ $logFile exists (Size: " . number_format($size) . " bytes, Modified: $modified)
";
if ($size > 0) {
echo "
View $logFile ";
}
} else {
echo "
⚠️ $logFile not found
";
}
}
echo "
";
// Identify likely issues
echo "";
echo "
🚨 Likely Issues ";
$issues = identifyIssues($db, $state, $recent);
foreach ($issues as $issue) {
echo "
{$issue['icon']} {$issue['message']}
";
}
echo "
";
// Provide solutions
echo "";
// Add JavaScript for log viewing
echo "";
}
function identifyIssues($db, $state, $recent) {
$issues = [];
// Check if truly stuck
if ($state && $state['is_running'] && $recent['count'] == 0) {
$issues[] = [
'type' => 'error',
'icon' => '🚨',
'message' => 'Background process is marked as running but no recent activity detected'
];
}
// Check if process file exists
if (!file_exists('enhanced_process_optimization.php') && !file_exists('process_optimization_analysis.php')) {
$issues[] = [
'type' => 'error',
'icon' => '❌',
'message' => 'No background process file found'
];
}
// Check PHP exec capability
if (!function_exists('exec')) {
$issues[] = [
'type' => 'error',
'icon' => '🚫',
'message' => 'PHP exec() function is disabled - background processes cannot run'
];
}
// Check if GptHelper is available
try {
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
if (!class_exists('GptHelper')) {
$issues[] = [
'type' => 'error',
'icon' => '🤖',
'message' => 'GptHelper class not found - GPT requests will fail'
];
}
} catch (Exception $e) {
$issues[] = [
'type' => 'error',
'icon' => '🤖',
'message' => 'GptHelper error: ' . $e->getMessage()
];
}
// Check OpenAI API key
if (!defined('OPENAI_API_KEY') || empty(OPENAI_API_KEY)) {
$issues[] = [
'type' => 'error',
'icon' => '🔑',
'message' => 'OpenAI API key not configured'
];
}
// Check for combinations to process
$pendingQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 0");
$pending = $pendingQuery->fetch_assoc()['count'];
if ($pending == 0) {
$issues[] = [
'type' => 'warning',
'icon' => '✅',
'message' => 'All combinations have been processed - analysis is complete!'
];
}
// If no major issues found
if (empty($issues) && $recent['count'] == 0) {
$issues[] = [
'type' => 'warning',
'icon' => '🤔',
'message' => 'Background process may have crashed silently or hit memory/time limits'
];
}
return $issues;
}
function handleAction($action, $db) {
switch ($action) {
case 'stop_and_restart':
stopAndRestart($db);
break;
case 'manual_process':
manualProcess($db);
break;
case 'foreground_test':
foregroundTest($db);
break;
case 'reset_state':
resetState($db);
break;
case 'check_permissions':
checkPermissions();
break;
case 'view_log':
viewLog($_GET['file'] ?? '');
exit;
default:
echo "❌ Unknown action: $action
";
}
echo "← Back to Diagnosis ";
}
function stopAndRestart($db) {
echo "🔄 Stop & Restart Analysis ";
try {
// Stop current analysis
$db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0 WHERE is_running = 1");
echo "✅ Stopped current analysis
";
sleep(2);
// Get current stats
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalQuery->fetch_assoc()['count'];
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$processedCount = $processedQuery->fetch_assoc()['count'];
// Start new analysis
$stmt = $db->prepare("INSERT INTO optimization_analysis_state
(total_combinations, processed_combinations, is_running, started_at, should_pause)
VALUES (?, ?, 1, NOW(), 0)");
$stmt->bind_param('ii', $totalCombinations, $processedCount);
if ($stmt->execute()) {
echo "✅ Created new analysis state
";
// Try to start background process
$processFile = file_exists('enhanced_process_optimization.php') ?
'enhanced_process_optimization.php' :
'process_optimization_analysis.php';
if (function_exists('exec')) {
$command = "php " . __DIR__ . "/$processFile > /dev/null 2>&1 &";
exec($command);
echo "✅ Started background process: $processFile
";
} else {
echo "❌ Cannot start background process - exec() disabled
";
echo "💡 Try 'Manual Processing' instead
";
}
} else {
echo "❌ Failed to create analysis state
";
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function manualProcess($db) {
echo "🔧 Manual Processing (Foreground) ";
echo "This will process combinations manually in the browser. Keep this page open.
";
try {
// Load GptHelper
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
if (!class_exists('GptHelper')) {
throw new Exception("GptHelper class not found");
}
echo "✅ GptHelper loaded
";
// Get a small batch to process
$batchSize = 5;
$query = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2, attribute1_name, attribute2_name
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT $batchSize
");
if (!$query || $query->num_rows == 0) {
echo "⚠️ No combinations to process
";
return;
}
echo "🔄 Processing " . $query->num_rows . " combinations...
";
$successCount = 0;
$errorCount = 0;
while ($combination = $query->fetch_assoc()) {
echo "";
echo "Processing: {$combination['attribute1_name']}={$combination['choice1']} + {$combination['attribute2_name']}={$combination['choice2']}";
try {
$result = processCombination($combination, $db);
if ($result['success']) {
$successCount++;
$status = $result['is_impossible'] ? 'IMPOSSIBLE' : 'POSSIBLE';
echo " → $status ";
} else {
$errorCount++;
echo " → ERROR: {$result['error']} ";
}
} catch (Exception $e) {
$errorCount++;
echo " → EXCEPTION: " . htmlspecialchars($e->getMessage()) . " ";
}
echo "
";
flush();
// Small delay to prevent overwhelming the API
sleep(1);
}
echo "✅ Manual processing complete: $successCount success, $errorCount errors
";
if ($successCount > 0) {
echo "💡 Manual processing is working. You can continue with 'Foreground Test' for more.
";
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function processCombination($combination, $db) {
try {
$prompt = sprintf(
"Analyze this demographic combination:\n\n%s = %s\n%s = %s\n\nIs this combination logically possible in real-world demographics? Respond with 'POSSIBLE' or 'IMPOSSIBLE' followed by a brief reason.",
$combination['attribute1_name'],
$combination['choice1'],
$combination['attribute2_name'],
$combination['choice2']
);
$messages = [
[
'role' => 'system',
'content' => 'You are an expert demographic analyst. Analyze if the given combination is logically possible.'
],
[
'role' => 'user',
'content' => $prompt
]
];
$response = GptHelper::makeRequest($messages, 'gpt-4', 0.1);
if (!$response['success']) {
throw new Exception("GPT request failed: " . $response['error']);
}
$content = trim($response['response']);
$isImpossible = stripos($content, 'IMPOSSIBLE') === 0 ? 1 : 0;
// Extract reasoning
$reasoning = trim(str_ireplace(['POSSIBLE', 'IMPOSSIBLE'], '', $content));
if (empty($reasoning)) {
$reasoning = $content;
}
// Update database
$stmt = $db->prepare("UPDATE panel_directives SET
llm_checked = 1,
is_impossible = ?,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?");
$stmt->bind_param('isi', $isImpossible, $reasoning, $combination['id']);
if (!$stmt->execute()) {
throw new Exception("Database update failed");
}
return [
'success' => true,
'is_impossible' => $isImpossible,
'reasoning' => $reasoning
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
function foregroundTest($db) {
echo "🧪 Foreground Processing Test ";
echo "⚠️ This will run continuous processing in your browser. Keep this tab open and active.
";
echo "Processing will continue until you close this page or all combinations are done.
";
echo " ";
// Add auto-refresh and processing script
echo "Starting...
";
echo "
";
echo "
";
echo "";
}
function resetState($db) {
echo "🗑 Reset Analysis State ";
try {
// Stop and reset analysis state
$db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0, completed_at = NOW()");
echo "✅ Analysis state reset
";
// Optionally reset progress (uncomment if needed)
// $db->query("UPDATE panel_directives SET llm_checked = 0, is_impossible = 0, llm_reasoning = NULL WHERE llm_checked = 1");
// echo "✅ Progress reset (all combinations marked as unprocessed)
";
echo "You can now start a fresh analysis from the OptimAIze page
";
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function checkPermissions() {
echo "🔐 File Permissions Check ";
$files = [
'enhanced_process_optimization.php',
'process_optimization_analysis.php',
'includes/GptHelper.php',
'includes/config.php'
];
foreach ($files as $file) {
if (file_exists($file)) {
$perms = substr(sprintf('%o', fileperms($file)), -4);
$readable = is_readable($file) ? '✅' : '❌';
$executable = is_executable($file) ? '✅' : '❌';
echo "$file: Permissions $perms | Readable $readable | Executable $executable
";
} else {
echo "❌ $file: Not found
";
}
}
// Check directory permissions
$writeable = is_writable('.') ? '✅' : '❌';
echo "Current directory writable: $writeable
";
}
function viewLog($filename) {
if (!in_array($filename, ['optimization_analysis.log', 'enhanced_optimization.log', 'error_log'])) {
echo "Invalid log file";
return;
}
if (!file_exists($filename)) {
echo "Log file not found: $filename";
return;
}
$content = file_get_contents($filename);
echo htmlspecialchars($content);
}
// Handle AJAX batch processing
if (isset($_GET['action']) && $_GET['action'] === 'process_batch') {
header('Content-Type: application/json');
try {
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
$batchSize = 3;
$query = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2, attribute1_name, attribute2_name
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT $batchSize
");
$combinations = [];
$processed = 0;
$errors = 0;
if ($query && $query->num_rows > 0) {
while ($combination = $query->fetch_assoc()) {
$result = processCombination($combination, $db);
$combinations[] = [
'combination' => "{$combination['attribute1_name']}={$combination['choice1']} + {$combination['attribute2_name']}={$combination['choice2']}",
'result' => $result['success'] ? ($result['is_impossible'] ? 'IMPOSSIBLE' : 'POSSIBLE') : 'ERROR'
];
if ($result['success']) {
$processed++;
} else {
$errors++;
}
}
}
// Check if more combinations exist
$remainingQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 0");
$hasMore = $remainingQuery->fetch_assoc()['count'] > 0;
echo json_encode([
'success' => true,
'processed' => $processed,
'errors' => $errors,
'combinations' => $combinations,
'has_more' => $hasMore
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
exit;
}
?>
-------------------- END OF FILE --------------------
### FILE 34: syndia.kreahealthcare.com/generate_optimized_panel.php
- Type: PHP
- Size: 1.66 KB
- Path: syndia.kreahealthcare.com
- Name: generate_optimized_panel.php
------------------------------------------------------------
query("DELETE FROM panel_data");
$db->query("DELETE FROM panel_processing_status");
$db->query("UPDATE statistic_combinations SET actual_percentage = NULL");
error_log("Cleared existing panel data");
// Start optimized generation
$result = $handler->generateOptimizedPanel(10000); // Generate 10,000 panelists
if ($result['success']) {
error_log("Optimized panel generation completed successfully");
error_log("Generated: " . $result['generated_count'] . " panelists");
error_log("Alignment score: " . ($result['alignment_score'] ?? 'N/A'));
error_log("Impossible combinations avoided: " . ($result['impossible_combinations_avoided'] ?? 0));
} else {
error_log("Optimized panel generation failed: " . $result['message']);
}
} catch (Exception $e) {
error_log("Error in optimized panel generation worker: " . $e->getMessage());
// Update session to indicate failure
$_SESSION['panel_generation_progress'] = 0;
$_SESSION['panel_generation_status'] = 'Error: ' . $e->getMessage();
}
?>
-------------------- END OF FILE --------------------
### FILE 35: syndia.kreahealthcare.com/generate_responses_worker.php
- Type: PHP
- Size: 15.06 KB
- Path: syndia.kreahealthcare.com
- Name: generate_responses_worker.php
------------------------------------------------------------
0,
'processed' => 0,
'success' => 0,
'error' => 0,
'total' => 0,
'status' => 'Started',
'completed' => false
];
file_put_contents($progress_file, json_encode($progress_data));
log_message("Progress file initialized");
// Reset GPT rate limits at the start - this is important
GptHelper::resetRateLimit();
// Function to get a fresh database connection
function getDbConnection() {
// Use the same credentials as in your config file
$conn = new mysqli('localhost', 'sridharmani', 'P@ssw0rd2016', 'syndia');
if ($conn->connect_error) {
throw new Exception("Connection failed: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
return $conn;
}
// Fetch all the data we need upfront to avoid multiple DB calls
try {
// Get selection details
$db = getDbConnection();
$stmt = $db->prepare("SELECT s.*, p.id as project_id FROM selections s JOIN projects p ON s.project_id = p.id WHERE s.id = ?");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$selection = $stmt->get_result()->fetch_assoc();
$db->close();
if (!$selection) {
throw new Exception("Selection not found");
}
// Get project's connected survey
$db = getDbConnection();
$stmt = $db->prepare("SELECT s.id as survey_id FROM project_surveys ps JOIN surveys s ON ps.survey_id = s.id WHERE ps.project_id = ? LIMIT 1");
$stmt->bind_param('i', $selection['project_id']);
$stmt->execute();
$connected_survey = $stmt->get_result()->fetch_assoc();
$db->close();
if (!$connected_survey) {
throw new Exception("No survey connected to project");
}
// Get survey questions
$db = getDbConnection();
$stmt = $db->prepare("SELECT id, question_text, question_type, options, config FROM survey_questions WHERE survey_id = ? AND question_type NOT IN ('section_header', 'descriptive_text', 'page_break') ORDER BY question_order ASC");
$stmt->bind_param('i', $connected_survey['survey_id']);
$stmt->execute();
$result = $stmt->get_result();
$questions = [];
while ($question = $result->fetch_assoc()) {
// Parse JSON fields if needed
if (!empty($question['options']) && is_string($question['options'])) {
$question['options'] = json_decode($question['options'], true);
}
if (!empty($question['config']) && is_string($question['config'])) {
$question['config'] = json_decode($question['config'], true);
}
$questions[] = $question;
}
$db->close();
// Get selection members
$db = getDbConnection();
$stmt = $db->prepare("SELECT sm.panelist_id, pd.attribute_values FROM selection_members sm LEFT JOIN panel_data pd ON sm.panelist_id = pd.panelist_id WHERE sm.selection_id = ? ORDER BY sm.id ASC");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$result = $stmt->get_result();
$members = [];
while ($member = $result->fetch_assoc()) {
$members[] = $member;
}
$db->close();
// Get all attributes
$db = getDbConnection();
$result = $db->query("SELECT id, name FROM attributes ORDER BY created_at ASC");
$attributes = [];
while ($attr = $result->fetch_assoc()) {
$attributes[$attr['id']] = $attr['name'];
}
$db->close();
// Clear existing responses
$db = getDbConnection();
$stmt = $db->prepare("DELETE FROM synthetic_responses WHERE selection_id = ?");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$db->close();
log_message("Cleared existing responses for selection");
$total_members = count($members);
$progress_data['total'] = $total_members;
file_put_contents($progress_file, json_encode($progress_data));
// Process each member
$processed = 0;
$success_count = 0;
$error_count = 0;
// Process members one by one
foreach ($members as $index => $member) {
log_message("Generating responses for member " . ($index + 1));
try {
// Extract member attributes for context
$attribute_values = json_decode($member['attribute_values'], true);
$profile_data = [];
foreach ($attribute_values as $attr_id => $value) {
if (isset($attributes[$attr_id])) {
$profile_data[$attributes[$attr_id]] = $value;
}
}
// Convert to readable format for GPT
$profile_text = "Respondent Profile:\n";
foreach ($profile_data as $attr => $value) {
$profile_text .= "- $attr: $value\n";
}
// Generate survey responses using GPT
$prompt = "You are acting as a synthetic survey respondent with the following demographic profile:\n\n";
$prompt .= $profile_text . "\n";
$prompt .= "Please generate authentic and realistic responses for the following survey questions. Your responses should reflect the perspective of someone with the demographic profile above.\n\n";
foreach ($questions as $i => $question) {
$prompt .= ($i+1) . ". " . $question['question_text'] . "\n";
// Add hints based on question type
if ($question['question_type'] == 'single_choice' || $question['question_type'] == 'dropdown') {
if (!empty($question['options'])) {
$prompt .= " Options: " . implode(", ", $question['options']) . "\n";
$prompt .= " (Select one option)\n";
}
} else if ($question['question_type'] == 'multiple_choice') {
if (!empty($question['options'])) {
$prompt .= " Options: " . implode(", ", $question['options']) . "\n";
$prompt .= " (Select one or more options, separate with commas)\n";
}
} else if ($question['question_type'] == 'rating_scale') {
$config = $question['config'] ?? [];
$start = $config['start'] ?? 1;
$end = $config['end'] ?? 5;
$prompt .= " (Provide a rating between $start and $end)\n";
}
}
$prompt .= "\nFormat your response as numbered answers only, with one answer per line. Don't include any explanations, just the direct response for each question.";
$responses = [];
$used_gpt = false;
$retry_count = 0;
$max_retries = 3;
// Try to use GPT with retry mechanism for rate limits
while (!$used_gpt && $retry_count < $max_retries) {
try {
// Use GPT to generate responses
$messages = [
['role' => 'system', 'content' => 'You are a synthetic survey respondent. Generate realistic responses based on the demographic profile provided.'],
['role' => 'user', 'content' => $prompt]
];
$gpt_response = GptHelper::makeRequest($messages);
log_message("GPT response received for member " . ($index + 1));
$response_lines = explode("\n", trim($gpt_response));
// Process response lines
foreach ($response_lines as $i => $line) {
// Strip line numbers if present (e.g., "1. Answer" -> "Answer")
$responses[] = preg_replace('/^\d+\.\s*/', '', $line);
}
// Ensure we have enough responses
while (count($responses) < count($questions)) {
$responses[] = "No response provided";
}
$used_gpt = true;
} catch (Exception $e) {
log_message("GPT error (attempt " . ($retry_count + 1) . "): " . $e->getMessage());
$retry_count++;
if (strpos($e->getMessage(), 'rate limit') !== false) {
// If rate limited, wait and retry
log_message("Rate limited, waiting 20 seconds before retry");
sleep(20); // Wait 20 seconds before retry
GptHelper::resetRateLimit(); // Reset rate limit tracker
} else if ($retry_count >= $max_retries) {
// If not rate limited and max retries reached, rethrow
throw $e;
}
}
}
// If GPT failed after all retries, use fallback approach
if (!$used_gpt) {
log_message("All GPT attempts failed for member " . ($index + 1) . ", using fallback approach");
// Basic fallback responses
foreach ($questions as $question) {
$qtype = $question['question_type'];
$qtext = $question['question_text'];
if ($qtype == 'single_choice' || $qtype == 'dropdown') {
$options = $question['options'] ?? [];
$responses[] = !empty($options) ? $options[array_rand($options)] : "No option selected";
}
else if ($qtype == 'multiple_choice') {
$options = $question['options'] ?? [];
if (!empty($options)) {
$numSelections = rand(1, min(3, count($options)));
$selectedIndices = array_rand($options, $numSelections);
if (!is_array($selectedIndices)) {
$selectedIndices = [$selectedIndices];
}
$selections = [];
foreach ($selectedIndices as $index) {
$selections[] = $options[$index];
}
$responses[] = implode(", ", $selections);
} else {
$responses[] = "No options selected";
}
}
else if ($qtype == 'rating_scale') {
$config = $question['config'] ?? [];
$min = $config['start'] ?? 1;
$max = $config['end'] ?? 5;
$responses[] = (string)rand($min, $max);
}
else {
$responses[] = "Fallback response";
}
}
}
// Insert all responses in a single transaction for efficiency
$db = getDbConnection();
$db->begin_transaction();
$success = true;
foreach ($questions as $q_index => $question) {
$response = isset($responses[$q_index]) ? $responses[$q_index] : "No response";
// Use direct query to avoid bind_param reference issues
$sql = sprintf(
"INSERT INTO synthetic_responses (selection_id, panelist_id, question_id, response_text) VALUES (%d, '%s', %d, '%s')",
$selection_id,
$db->real_escape_string($member['panelist_id']),
$question['id'],
$db->real_escape_string($response)
);
if (!$db->query($sql)) {
$success = false;
log_message("Failed to insert response: " . $db->error);
break;
}
}
if ($success) {
$db->commit();
$success_count++;
} else {
$db->rollback();
$error_count++;
}
$db->close();
} catch (Exception $e) {
log_message("Error generating responses: " . $e->getMessage());
$error_count++;
}
$processed++;
$progress = ($processed / $total_members) * 100;
// Update progress
$progress_data = [
'progress' => $progress,
'processed' => $processed,
'success' => $success_count,
'error' => $error_count,
'total' => $total_members,
'status' => "Generated responses for $processed of $total_members members",
'completed' => ($processed >= $total_members)
];
file_put_contents($progress_file, json_encode($progress_data));
log_message("Progress updated for member " . $processed);
}
// Final progress update
$progress_data = [
'progress' => 100,
'processed' => $total_members,
'success' => $success_count,
'error' => $error_count,
'total' => $total_members,
'status' => "Completed with $success_count successful and $error_count failed",
'completed' => true
];
file_put_contents($progress_file, json_encode($progress_data));
log_message("Test completed successfully");
log_message("Worker script finished");
} catch (Exception $e) {
log_message("Fatal error: " . $e->getMessage());
$progress_data = [
'progress' => 0,
'processed' => 0,
'success' => 0,
'error' => 1,
'total' => 0,
'status' => "Error: " . $e->getMessage(),
'completed' => true
];
file_put_contents($progress_file, json_encode($progress_data));
}
?>
-------------------- END OF FILE --------------------
### FILE 36: syndia.kreahealthcare.com/generate_responses.php
- Type: PHP
- Size: 12.31 KB
- Path: syndia.kreahealthcare.com
- Name: generate_responses.php
------------------------------------------------------------
isLoggedIn()) {
$_SESSION['error_message'] = 'Unauthorized';
redirectTo('projects.php');
exit;
}
$db = Database::getInstance();
$selection_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$selection_id) {
$_SESSION['error_message'] = 'Invalid selection ID';
redirectTo('projects.php');
exit;
}
// Get selection details with project information
$stmt = $db->prepare("
SELECT s.*, p.id as project_id, p.title as project_title,
DATE_FORMAT(s.created_at, '%b %d, %Y %H:%i') as formatted_date
FROM selections s
JOIN projects p ON s.project_id = p.id
WHERE s.id = ? AND p.created_by = ?
");
$stmt->bind_param('ii', $selection_id, $_SESSION['user_id']);
$stmt->execute();
$selection = $stmt->get_result()->fetch_assoc();
if (!$selection) {
$_SESSION['error_message'] = 'Selection not found or access denied';
redirectTo('projects.php');
exit;
}
// Get project's connected survey
$stmt = $db->prepare("
SELECT s.id as survey_id, s.title as survey_title
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = ?
LIMIT 1
");
$stmt->bind_param('i', $selection['project_id']);
$stmt->execute();
$connected_survey = $stmt->get_result()->fetch_assoc();
if (!$connected_survey) {
$_SESSION['error_message'] = 'No survey connected to this project';
redirectTo("manage_project.php?id={$selection['project_id']}");
exit;
}
// Check if we've already generated responses
$stmt = $db->prepare("
SELECT COUNT(*) as count FROM synthetic_responses
WHERE selection_id = ?
");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
$has_responses = $stmt->get_result()->fetch_assoc()['count'] > 0;
if ($has_responses) {
if (isset($_GET['force']) && $_GET['force'] == 1) {
// Delete existing responses if force parameter is provided
$stmt = $db->prepare("DELETE FROM synthetic_responses WHERE selection_id = ?");
$stmt->bind_param('i', $selection_id);
$stmt->execute();
} else {
$_SESSION['error_message'] = 'Responses already generated for this selection. Click here to regenerate.';
redirectTo("manage_project.php?id={$selection['project_id']}");
exit;
}
}
// Initialize progress file
$progress_file = sys_get_temp_dir() . '/syndia_progress_' . $selection_id . '.json';
$progress_data = [
'progress' => 0,
'processed' => 0,
'success' => 0,
'error' => 0,
'total' => 0,
'status' => 'Initializing...',
'completed' => false
];
file_put_contents($progress_file, json_encode($progress_data));
// Start the background process
$phpBinary = PHP_BINARY;
$scriptPath = dirname(__FILE__) . '/generate_responses_worker.php';
$logPath = dirname(__FILE__) . '/logs';
// Create logs directory if it doesn't exist
if (!file_exists($logPath)) {
mkdir($logPath, 0777, true);
}
$logFile = $logPath . '/generate_responses_' . $selection_id . '.log';
$cmd = sprintf(
'nohup %s %s %d > %s 2>&1 & echo $!',
escapeshellarg($phpBinary),
escapeshellarg($scriptPath),
$selection_id,
escapeshellarg($logFile)
);
error_log("Executing command: $cmd");
$output = [];
exec($cmd, $output, $returnVal);
error_log("Command execution result - Return value: $returnVal, Output: " . print_r($output, true));
// Create progress tracking page
?>
Generating Responses |
Generating Survey Responses
We're creating synthetic responses for selection:
Initializing response generation...
-------------------- END OF FILE --------------------
### FILE 37: syndia.kreahealthcare.com/get_attribute_choices.php
- Type: PHP
- Size: 3.85 KB
- Path: syndia.kreahealthcare.com
- Name: get_attribute_choices.php
------------------------------------------------------------
isLoggedIn()) {
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$db = Database::getInstance();
// Support both GET and POST for backward compatibility
$attribute_id = $_POST['attribute_id'] ?? $_GET['attribute_id'] ?? '';
if (empty($attribute_id)) {
echo json_encode(['success' => false, 'message' => 'Attribute ID is required']);
exit;
}
try {
// Get attribute details - using correct column names
$stmt = $db->prepare("SELECT * FROM attributes WHERE id = ?");
$stmt->bind_param('i', $attribute_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
throw new Exception('Attribute not found');
}
$attribute = $result->fetch_assoc();
$choices = [];
// Get choices based on attribute choice_type (correct column name)
if ($attribute['choice_type'] === 'multiple' || $attribute['choice_type'] === 'single') {
// For multiple choice and single choice, get predefined options first
$predefined_choices = json_decode($attribute['choices'], true); // correct column name
if (is_array($predefined_choices)) {
foreach ($predefined_choices as $choice) {
if (!in_array($choice, $choices)) {
$choices[] = $choice; // Keep as string for backward compatibility
}
}
}
}
// Additionally, get unique values from panel data for this attribute
$query = "SELECT DISTINCT JSON_EXTRACT(attribute_values, '$.\"$attribute_id\"') as value
FROM panel_data
WHERE JSON_EXTRACT(attribute_values, '$.\"$attribute_id\"') IS NOT NULL
AND JSON_EXTRACT(attribute_values, '$.\"$attribute_id\"') != 'null'
ORDER BY value";
$result = $db->query($query);
if ($result) {
while ($row = $result->fetch_assoc()) {
$value = $row['value'];
// Clean up the value (remove quotes and handle JSON arrays)
$value = trim($value, '"');
// Skip empty values
if (empty($value) || $value === 'null') {
continue;
}
// Handle JSON arrays (for multiple values)
if (substr($value, 0, 1) === '[' && substr($value, -1) === ']') {
$array_values = json_decode($value, true);
if (is_array($array_values)) {
foreach ($array_values as $array_value) {
if (!empty($array_value) && !in_array($array_value, $choices)) {
$choices[] = $array_value; // Keep as string for backward compatibility
}
}
continue;
}
}
// Add single value if not already in choices
if (!in_array($value, $choices)) {
$choices[] = $value; // Keep as string for backward compatibility
}
}
}
// Sort choices alphabetically
sort($choices);
// Return format compatible with existing OptimAIze usage
echo json_encode([
'success' => true,
'choices' => $choices, // Array of strings, not objects
'attribute_name' => $attribute['name'],
'attribute_type' => $attribute['choice_type']
]);
} catch (Exception $e) {
error_log("Error getting attribute choices: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => 'Failed to load choices: ' . $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 38: syndia.kreahealthcare.com/get_available_count.php
- Type: PHP
- Size: 3.84 KB
- Path: syndia.kreahealthcare.com
- Name: get_available_count.php
------------------------------------------------------------
isLoggedIn()) {
die(json_encode(['success' => false, 'message' => 'Unauthorized']));
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die(json_encode(['success' => false, 'message' => 'Invalid request method']));
}
$db = Database::getInstance();
$project_id = isset($_POST['project_id']) ? (int)$_POST['project_id'] : 0;
if (!$project_id) {
die(json_encode(['success' => false, 'message' => 'Invalid project ID']));
}
// Verify user has access to this project
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
die(json_encode(['success' => false, 'message' => 'Access denied']));
}
// Get POST data for filters
$filters = isset($_POST['filters']) ? json_decode($_POST['filters'], true) : [];
// Get all previously used panelist IDs in this project's selections
$stmt = $db->prepare("
SELECT DISTINCT panelist_id
FROM selection_members sm
JOIN selections s ON sm.selection_id = s.id
WHERE s.project_id = ?
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$used_panelists_result = $stmt->get_result();
$used_panelists = [];
while ($row = $used_panelists_result->fetch_assoc()) {
$used_panelists[] = $row['panelist_id'];
}
// Build WHERE clause based on filter criteria
$where_conditions = [];
// If we have used panelists, exclude them
if (!empty($used_panelists)) {
$used_panelists_str = "'" . implode("','", $used_panelists) . "'";
$where_conditions[] = "panelist_id NOT IN ($used_panelists_str)";
}
// Process filter criteria from attributes
if (!empty($filters)) {
// Get attribute types
$attr_types = [];
$attr_query = $db->query("SELECT id, choice_type FROM attributes");
while ($attr = $attr_query->fetch_assoc()) {
$attr_types[$attr['id']] = $attr['choice_type'];
}
foreach ($filters as $attr_id => $value) {
if (!empty($value)) {
// Skip attr_ prefix in keys if present
$attr_id = str_replace('attr_', '', $attr_id);
$choice_type = $attr_types[$attr_id] ?? 'single';
if ($choice_type === 'single') {
// Single choice attributes
$value = $db->escape($value);
$where_conditions[] = "JSON_UNQUOTE(JSON_EXTRACT(attribute_values, '$.{$attr_id}')) = '{$value}'";
} else if ($choice_type === 'multiple' && is_array($value) && !empty($value)) {
// Multiple choice attributes
$or_conditions = [];
foreach ($value as $v) {
$escaped_value = $db->escape($v);
// Use JSON_CONTAINS to check if array contains the value
$or_conditions[] = "JSON_CONTAINS(attribute_values, '\"{$escaped_value}\"', '$.{$attr_id}')";
}
if (!empty($or_conditions)) {
$where_conditions[] = '(' . implode(' OR ', $or_conditions) . ')';
}
}
}
}
}
// Build the SQL query to get count of eligible panelists
$sql = "SELECT COUNT(*) as count FROM panel_data";
if (!empty($where_conditions)) {
$sql .= " WHERE " . implode(' AND ', $where_conditions);
}
// For debugging
error_log("Available count SQL: " . $sql);
// Get the count
$result = $db->query($sql);
if (!$result) {
die(json_encode(['success' => false, 'message' => 'Error querying panel data: ' . $db->getLastError()]));
}
$available_count = $result->fetch_assoc()['count'];
// Return the count
echo json_encode([
'success' => true,
'count' => (int)$available_count
]);
?>
-------------------- END OF FILE --------------------
### FILE 39: syndia.kreahealthcare.com/get_available_surveys.php
- Type: PHP
- Size: 2.38 KB
- Path: syndia.kreahealthcare.com
- Name: get_available_surveys.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$projectId = isset($_GET['project_id']) ? (int)$_GET['project_id'] : null;
if (!$projectId) {
throw new Exception('Project ID is required');
}
$db = Database::getInstance();
// Check if the project exists and user has access
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $projectId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows == 0) {
throw new Exception('Project not found or access denied');
}
// Get surveys that are not already connected to this project
// First, create a SQL query to get all active surveys that aren't already connected
$sql = "SELECT s.*
FROM surveys s
LEFT JOIN project_surveys ps ON s.id = ps.survey_id AND ps.project_id = ?
WHERE s.status = 'active'
AND s.created_by = ?
AND ps.id IS NULL
ORDER BY s.created_at DESC";
$stmt = $db->prepare($sql);
$stmt->bind_param('ii', $projectId, $_SESSION['user_id']);
$stmt->execute();
$result = $stmt->get_result();
$surveys = [];
while ($row = $result->fetch_assoc()) {
// Add additional data to each survey
$questionsCount = $db->query("SELECT COUNT(*) as count FROM survey_questions WHERE survey_id = " . $row['id'])->fetch_assoc()['count'];
$tokensCount = $db->query("SELECT COUNT(*) as count FROM survey_tokens WHERE survey_id = " . $row['id'])->fetch_assoc()['count'];
$responsesCount = $db->query("SELECT COUNT(*) as count FROM survey_tokens WHERE survey_id = " . $row['id'] . " AND is_completed = 1")->fetch_assoc()['count'];
$row['questions_count'] = $questionsCount;
$row['tokens_count'] = $tokensCount;
$row['responses_count'] = $responsesCount;
$surveys[] = $row;
}
echo json_encode([
'success' => true,
'surveys' => $surveys
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 40: syndia.kreahealthcare.com/get_connected_surveys.php
- Type: PHP
- Size: 1.93 KB
- Path: syndia.kreahealthcare.com
- Name: get_connected_surveys.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$projectId = isset($_GET['project_id']) ? (int)$_GET['project_id'] : null;
if (!$projectId) {
throw new Exception('Project ID is required');
}
$db = Database::getInstance();
// Check if the project exists and user has access
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $projectId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows == 0) {
throw new Exception('Project not found or access denied');
}
// Get surveys that are connected to this project with additional data
$sql = "SELECT ps.id as connection_id, s.*,
(SELECT COUNT(DISTINCT q.id) FROM survey_questions q WHERE q.survey_id = s.id) as questions_count,
(SELECT COUNT(DISTINCT t.id) FROM survey_tokens t WHERE t.survey_id = s.id) as tokens_count,
(SELECT COUNT(DISTINCT t.id) FROM survey_tokens t WHERE t.survey_id = s.id AND t.is_completed = 1) as responses_count
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = ?
ORDER BY ps.created_at DESC";
$stmt = $db->prepare($sql);
$stmt->bind_param('i', $projectId);
$stmt->execute();
$result = $stmt->get_result();
$surveys = [];
while ($row = $result->fetch_assoc()) {
$surveys[] = $row;
}
echo json_encode([
'success' => true,
'surveys' => $surveys
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 41: syndia.kreahealthcare.com/get_impossible_combinations.php
- Type: PHP
- Size: 2.84 KB
- Path: syndia.kreahealthcare.com
- Name: get_impossible_combinations.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ? max(1, min(100, (int)$_GET['limit'])) : 10;
$offset = ($page - 1) * $limit;
$db = Database::getInstance();
// Get total count of impossible combinations
$countQuery = $db->query("
SELECT COUNT(*) as total
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 1
");
$totalCount = $countQuery ? $countQuery->fetch_assoc()['total'] : 0;
$totalPages = ceil($totalCount / $limit);
// Get paginated impossible combinations
$stmt = $db->prepare("
SELECT
id,
attribute1_id,
attribute2_id,
choice1,
choice2,
attribute1_name,
attribute2_name,
status,
llm_reasoning,
updated_at
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 1
ORDER BY updated_at DESC
LIMIT ? OFFSET ?
");
$stmt->bind_param('ii', $limit, $offset);
$stmt->execute();
$result = $stmt->get_result();
$combinations = [];
while ($row = $result->fetch_assoc()) {
$combinations[] = [
'id' => (int)$row['id'],
'attribute1_id' => (int)$row['attribute1_id'],
'attribute2_id' => (int)$row['attribute2_id'],
'choice1' => $row['choice1'],
'choice2' => $row['choice2'],
'attribute1_name' => $row['attribute1_name'],
'attribute2_name' => $row['attribute2_name'],
'status' => $row['status'],
'reasoning' => $row['llm_reasoning'],
'updated_at' => $row['updated_at']
];
}
echo json_encode([
'success' => true,
'combinations' => $combinations,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => (int)$totalCount,
'totalPages' => (int)$totalPages,
'hasNext' => $page < $totalPages,
'hasPrev' => $page > 1
],
// Legacy fields for compatibility
'page' => $page,
'total' => (int)$totalCount,
'totalPages' => (int)$totalPages
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage(),
'combinations' => [],
'pagination' => [
'page' => 1,
'limit' => 10,
'total' => 0,
'totalPages' => 0,
'hasNext' => false,
'hasPrev' => false
]
]);
}
-------------------- END OF FILE --------------------
### FILE 42: syndia.kreahealthcare.com/get_optimization_progress.php
- Type: PHP
- Size: 5.74 KB
- Path: syndia.kreahealthcare.com
- Name: get_optimization_progress.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$db = Database::getInstance();
// Get current analysis state (no caching)
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
// Get FRESH real-time statistics - force fresh database query
$stats = getCurrentStatsFresh($db);
// Calculate processing rate
$processingRate = calculateProcessingRate($db);
// Estimate time remaining
$timeRemaining = estimateTimeRemaining($stats, $processingRate);
// Check for recent activity
$recentActivity = checkRecentActivity($db);
// Add debug timestamp to verify fresh data
$debug_info = [
'query_time' => date('Y-m-d H:i:s'),
'microtime' => microtime(true),
'cache_buster' => time()
];
echo json_encode([
'success' => true,
'is_running' => $state ? (bool)$state['is_running'] : false,
'should_pause' => $state ? (bool)$state['should_pause'] : false,
'stats' => $stats,
'processing_rate' => $processingRate,
'time_remaining' => $timeRemaining,
'recent_activity' => $recentActivity,
'started_at' => $state ? $state['started_at'] : null,
'last_updated' => $state ? $state['last_updated'] : null,
'debug' => $debug_info
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage(),
'debug' => [
'error_time' => date('Y-m-d H:i:s'),
'error_file' => __FILE__
]
]);
}
// ENHANCED: Force fresh statistics with better queries
function getCurrentStatsFresh($db) {
$stats = [];
try {
// Force fresh queries by using NOW() in query to prevent any MySQL query caching
// Total combinations
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE created_at <= NOW()");
$stats['total'] = $totalQuery ? (int)$totalQuery->fetch_assoc()['count'] : 0;
// Processed combinations (force fresh read)
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND updated_at <= NOW()");
$stats['processed'] = $processedQuery ? (int)$processedQuery->fetch_assoc()['count'] : 0;
// Impossible combinations (force fresh read)
$impossibleQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1 AND updated_at <= NOW()");
$stats['impossible'] = $impossibleQuery ? (int)$impossibleQuery->fetch_assoc()['count'] : 0;
// Progress percentage
$stats['progress'] = $stats['total'] > 0 ? ($stats['processed'] / $stats['total']) * 100 : 0;
// Optimization rate
$stats['optimization_rate'] = $stats['total'] > 0 ? ($stats['impossible'] / $stats['total']) * 100 : 0;
// Remaining combinations
$stats['remaining'] = $stats['total'] - $stats['processed'];
// Add timestamp for debugging
$stats['fetched_at'] = date('Y-m-d H:i:s');
return $stats;
} catch (Exception $e) {
error_log("Error getting fresh stats: " . $e->getMessage());
return [
'total' => 0,
'processed' => 0,
'impossible' => 0,
'progress' => 0,
'optimization_rate' => 0,
'remaining' => 0,
'fetched_at' => date('Y-m-d H:i:s'),
'error' => $e->getMessage()
];
}
}
function calculateProcessingRate($db) {
try {
// Calculate combinations processed in the last hour
$hourlyQuery = $db->query("
SELECT COUNT(*) as count
FROM panel_directives
WHERE llm_checked = 1
AND updated_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
");
$hourlyProcessed = $hourlyQuery ? $hourlyQuery->fetch_assoc()['count'] : 0;
// Calculate rate per minute
$rate = $hourlyProcessed / 60;
return max(0, $rate);
} catch (Exception $e) {
return 0;
}
}
function estimateTimeRemaining($stats, $processingRate) {
try {
if ($processingRate <= 0 || $stats['remaining'] <= 0) {
return null;
}
$minutesRemaining = $stats['remaining'] / $processingRate;
if ($minutesRemaining < 60) {
return round($minutesRemaining) . ' minutes';
} else if ($minutesRemaining < 1440) { // Less than 24 hours
return round($minutesRemaining / 60, 1) . ' hours';
} else {
return round($minutesRemaining / 1440, 1) . ' days';
}
} catch (Exception $e) {
return null;
}
}
function checkRecentActivity($db) {
try {
// Check if any combinations were processed in the last 5 minutes
$recentQuery = $db->query("
SELECT COUNT(*) as count
FROM panel_directives
WHERE llm_checked = 1
AND updated_at >= DATE_SUB(NOW(), INTERVAL 5 MINUTE)
");
$recentCount = $recentQuery ? $recentQuery->fetch_assoc()['count'] : 0;
return $recentCount > 0;
} catch (Exception $e) {
return false;
}
}
?>
-------------------- END OF FILE --------------------
### FILE 43: syndia.kreahealthcare.com/get_panelist_details.php
- Type: PHP
- Size: 3.18 KB
- Path: syndia.kreahealthcare.com
- Name: get_panelist_details.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized access
');
}
$db = Database::getInstance();
// Get panelist ID from URL
$panelist_id = isset($_GET['id']) ? sanitizeInput($_GET['id']) : '';
if (empty($panelist_id)) {
die('Invalid panelist ID
');
}
// Get panelist details
$stmt = $db->prepare("SELECT * FROM panel_data WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
$panelist = $stmt->get_result()->fetch_assoc();
if (!$panelist) {
die('Panelist not found
');
}
// Get all attributes
$attributes = [];
$attr_query = $db->query("SELECT id, name, choice_type, choices FROM attributes ORDER BY created_at ASC");
while ($attr = $attr_query->fetch_assoc()) {
$attributes[$attr['id']] = $attr;
}
// Parse attribute values
$attribute_values = json_decode($panelist['attribute_values'], true);
?>
-------------------- END OF FILE --------------------
### FILE 44: syndia.kreahealthcare.com/get_recent_combinations.php
- Type: PHP
- Size: 3.31 KB
- Path: syndia.kreahealthcare.com
- Name: get_recent_combinations.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$type = $_GET['type'] ?? 'possible';
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : null;
if (!in_array($type, ['possible', 'impossible'])) {
throw new Exception('Invalid type. Must be "possible" or "impossible"');
}
$db = Database::getInstance();
$combinations = getCombinations($db, $type, $limit);
echo json_encode([
'success' => true,
'type' => $type,
'count' => count($combinations),
'combinations' => $combinations
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
function getCombinations($db, $type, $limit) {
try {
$isImpossible = $type === 'impossible' ? 1 : 0;
$sql = "SELECT
id,
attribute1_id,
attribute2_id,
choice1,
choice2,
attribute1_name,
attribute2_name,
is_impossible,
llm_reasoning,
updated_at
FROM panel_directives
WHERE llm_checked = 1
AND is_impossible = ?
ORDER BY updated_at DESC";
if ($limit) {
$sql .= " LIMIT ?";
}
$stmt = $db->prepare($sql);
if ($limit) {
$stmt->bind_param('ii', $isImpossible, $limit);
} else {
$stmt->bind_param('i', $isImpossible);
}
$stmt->execute();
$result = $stmt->get_result();
$combinations = [];
while ($row = $result->fetch_assoc()) {
$combinations[] = [
'id' => $row['id'],
'attribute1_id' => $row['attribute1_id'],
'attribute2_id' => $row['attribute2_id'],
'choice1' => $row['choice1'],
'choice2' => $row['choice2'],
'attribute1_name' => $row['attribute1_name'],
'attribute2_name' => $row['attribute2_name'],
'is_impossible' => (bool)$row['is_impossible'],
'reasoning' => $row['llm_reasoning'],
'updated_at' => $row['updated_at'],
'formatted_time' => formatTimeAgo($row['updated_at'])
];
}
return $combinations;
} catch (Exception $e) {
error_log("Error getting combinations: " . $e->getMessage());
return [];
}
}
function formatTimeAgo($datetime) {
$time = time() - strtotime($datetime);
if ($time < 60) {
return 'Just now';
} elseif ($time < 3600) {
$minutes = floor($time / 60);
return $minutes . ' minute' . ($minutes > 1 ? 's' : '') . ' ago';
} elseif ($time < 86400) {
$hours = floor($time / 3600);
return $hours . ' hour' . ($hours > 1 ? 's' : '') . ' ago';
} else {
$days = floor($time / 86400);
return $days . ' day' . ($days > 1 ? 's' : '') . ' ago';
}
}
?>
-------------------- END OF FILE --------------------
### FILE 45: syndia.kreahealthcare.com/get_selection_form.php
- Type: PHP
- Size: 7.27 KB
- Path: syndia.kreahealthcare.com
- Name: get_selection_form.php
------------------------------------------------------------
isLoggedIn()) {
die('Unauthorized');
}
$db = Database::getInstance();
$project_id = isset($_GET['project_id']) ? (int)$_GET['project_id'] : 0;
if (!$project_id) {
die('Invalid project ID');
}
// Verify user has access to this project
$stmt = $db->prepare("SELECT id FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
die('Access denied');
}
// Get all attributes for the selection form
$attributes = $db->query("SELECT id, name, choice_type, choices FROM attributes ORDER BY created_at ASC");
// Get all previously used panelist IDs in this project's selections to exclude them from available count
$stmt = $db->prepare("
SELECT DISTINCT panelist_id
FROM selection_members sm
JOIN selections s ON sm.selection_id = s.id
WHERE s.project_id = ?
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$used_panelists_result = $stmt->get_result();
$used_panelists = [];
while ($row = $used_panelists_result->fetch_assoc()) {
$used_panelists[] = $row['panelist_id'];
}
// Convert used panelists to JSON for JavaScript
$used_panelists_json = json_encode($used_panelists);
// Get total available (unused) panelists count
$used_panelists_str = empty($used_panelists) ? "''" : "'" . implode("','", $used_panelists) . "'";
$available_count_query = "SELECT COUNT(*) as count FROM panel_data WHERE panelist_id NOT IN ($used_panelists_str)";
$available_count_result = $db->query($available_count_query);
$available_count = 0;
if ($available_count_result) {
$available_count = $available_count_result->fetch_assoc()['count'];
}
?>
Selection Name
Give this selection a descriptive name
Filter Criteria
num_rows > 0): ?>
fetch_assoc()): ?>
No attributes found. Please add attributes in the Base section first.
-------------------- END OF FILE --------------------
### FILE 46: syndia.kreahealthcare.com/get_survey_questions.php
- Type: PHP
- Size: 2.71 KB
- Path: syndia.kreahealthcare.com
- Name: get_survey_questions.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$surveyId = isset($_GET['survey_id']) ? (int)$_GET['survey_id'] : null;
$questionId = isset($_GET['question_id']) ? (int)$_GET['question_id'] : null;
if (!$surveyId) {
throw new Exception('Survey ID is required');
}
$db = Database::getInstance();
// Check if survey exists and user has access
$stmt = $db->prepare("SELECT * FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
$survey = $stmt->get_result()->fetch_assoc();
if (!$survey) {
throw new Exception('Survey not found or access denied');
}
// Get questions
if ($questionId) {
// Get specific question
$stmt = $db->prepare("SELECT * FROM survey_questions WHERE id = ? AND survey_id = ?");
$stmt->bind_param('ii', $questionId, $surveyId);
$stmt->execute();
$question = $stmt->get_result()->fetch_assoc();
if (!$question) {
throw new Exception('Question not found');
}
// Parse JSON fields
if (!empty($question['options'])) {
$question['options'] = json_decode($question['options'], true);
}
if (!empty($question['config'])) {
$question['config'] = json_decode($question['config'], true);
}
echo json_encode([
'success' => true,
'question' => $question
]);
} else {
// Get all questions
$stmt = $db->prepare("SELECT * FROM survey_questions WHERE survey_id = ? ORDER BY question_order ASC");
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$result = $stmt->get_result();
$questions = [];
while ($question = $result->fetch_assoc()) {
// Parse JSON fields
if (!empty($question['options'])) {
$question['options'] = json_decode($question['options'], true);
}
if (!empty($question['config'])) {
$question['config'] = json_decode($question['config'], true);
}
$questions[] = $question;
}
echo json_encode([
'success' => true,
'questions' => $questions
]);
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 47: syndia.kreahealthcare.com/get_surveys.php
- Type: PHP
- Size: 823 B
- Path: syndia.kreahealthcare.com
- Name: get_surveys.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$surveyManager = SurveyManager::getInstance();
// Get filter parameters
$filters = [
'status' => $_GET['status'] ?? '',
'search' => $_GET['search'] ?? ''
];
// Get surveys with stats
$surveys = $surveyManager->getSurveys($_SESSION['user_id'], $filters);
echo json_encode([
'success' => true,
'surveys' => $surveys
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 48: syndia.kreahealthcare.com/impossible_combinations_api.php
- Type: PHP
- Size: 3.42 KB
- Path: syndia.kreahealthcare.com
- Name: impossible_combinations_api.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$db = Database::getInstance();
$action = $_GET['action'] ?? $_POST['action'] ?? '';
switch ($action) {
case 'get_impossible_combinations':
getImpossibleCombinations($db);
break;
case 'update_directive_status':
updateDirectiveStatus($db);
break;
default:
throw new Exception('Invalid action');
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
function getImpossibleCombinations($db) {
$page = (int)($_GET['page'] ?? 1);
$limit = (int)($_GET['limit'] ?? 10);
$offset = ($page - 1) * $limit;
// Get total count
$countQuery = $db->query("SELECT COUNT(*) as total FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1");
$total = $countQuery->fetch_assoc()['total'];
// Get paginated results with directive ID generation
$query = $db->prepare("
SELECT
id,
attribute1_name,
choice1,
attribute2_name,
choice2,
llm_reasoning,
status,
updated_at,
CONCAT('SYD', LPAD(id, 6, '0')) as directive_id
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 1
ORDER BY updated_at DESC
LIMIT ? OFFSET ?
");
$query->bind_param('ii', $limit, $offset);
$query->execute();
$result = $query->get_result();
$combinations = [];
while ($row = $result->fetch_assoc()) {
$combinations[] = [
'id' => $row['id'],
'directive_id' => $row['directive_id'],
'combination' => "{$row['attribute1_name']} = {$row['choice1']} + {$row['attribute2_name']} = {$row['choice2']}",
'reasoning' => $row['llm_reasoning'],
'status' => $row['status'] ?? 'pending',
'updated_at' => $row['updated_at']
];
}
echo json_encode([
'success' => true,
'combinations' => $combinations,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => (int)$total,
'total_pages' => ceil($total / $limit)
]
]);
}
function updateDirectiveStatus($db) {
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['id']) || !isset($input['status'])) {
throw new Exception('Missing required parameters');
}
$id = (int)$input['id'];
$status = $input['status'];
// Validate status
if (!in_array($status, ['pending', 'approved', 'declined'])) {
throw new Exception('Invalid status');
}
$stmt = $db->prepare("UPDATE panel_directives SET status = ?, updated_at = NOW() WHERE id = ?");
$stmt->bind_param('si', $status, $id);
if (!$stmt->execute()) {
throw new Exception('Failed to update directive status');
}
if ($stmt->affected_rows === 0) {
throw new Exception('Directive not found');
}
echo json_encode([
'success' => true,
'message' => 'Directive status updated successfully'
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 49: syndia.kreahealthcare.com/index.php
- Type: PHP
- Size: 1001 B
- Path: syndia.kreahealthcare.com
- Name: index.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('dashboard.php');
}
try {
$db = Database::getInstance();
$result = $db->query("SELECT COUNT(*) as count FROM users");
if (!$result) {
error_log("Database error: " . $db->getLastError());
die("An error occurred while checking the database.");
}
$row = $result->fetch_assoc();
// If no users exist, redirect to register page for initial admin setup
if ($row['count'] === '0') {
redirectTo('register.php');
} else {
// Otherwise redirect to login page
redirectTo('login.php');
}
} catch (Exception $e) {
error_log("Error in index.php: " . $e->getMessage());
die("An error occurred while accessing the application. Please try again later.");
}
-------------------- END OF FILE --------------------
### FILE 50: syndia.kreahealthcare.com/init_admin.php
- Type: PHP
- Size: 1.68 KB
- Path: syndia.kreahealthcare.com
- Name: init_admin.php
------------------------------------------------------------
";
try {
$db = Database::getInstance();
echo "Database connected successfully. ";
// Check if admin exists
$result = $db->query("SELECT COUNT(*) as count FROM users WHERE role = 'admin'");
if (!$result) {
throw new Exception("Query failed: " . $db->getLastError());
}
$row = $result->fetch_assoc();
if ($row['count'] === '0') {
$password = password_hash('Admin@123', PASSWORD_DEFAULT);
$sql = "INSERT INTO users (full_name, email, phone, whatsapp, password, role)
VALUES ('Admin User', 'admin@syndia.com', '1234567890', '1234567890', '$password', 'admin')";
if ($db->query($sql)) {
echo "";
echo "Initial admin account created successfully! ";
echo "Email: admin@syndia.com ";
echo "Password: Admin@123 ";
echo "
";
echo "Go to Login ";
} else {
throw new Exception("Error creating admin user: " . $db->getLastError());
}
} else {
echo "Admin already exists. Go to Login ";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "
";
}
-------------------- END OF FILE --------------------
### FILE 51: syndia.kreahealthcare.com/integrity_check_handler.php
- Type: PHP
- Size: 32.87 KB
- Path: syndia.kreahealthcare.com
- Name: integrity_check_handler.php
------------------------------------------------------------
isLoggedIn()) {
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$db = Database::getInstance();
$action = $_POST['action'] ?? '';
// Create necessary tables if they don't exist
createIntegrityTables($db);
// Clean any output that might have been generated
$output = ob_get_clean();
if (!empty($output)) {
error_log("Unexpected output in integrity_check_handler: " . $output);
}
switch ($action) {
case 'get_directives':
echo json_encode(getDirectives($db));
break;
case 'create_directive':
echo json_encode(createDirective($db, $_POST));
break;
case 'approve_directive':
echo json_encode(approveDirective($db, $_POST['directive_id']));
break;
case 'delete_directive':
echo json_encode(deleteDirective($db, $_POST['directive_id']));
break;
case 'start_integrity_check':
echo json_encode(startIntegrityCheck($db));
break;
case 'get_check_status':
echo json_encode(getCheckStatus($db));
break;
case 'get_check_progress':
echo json_encode(getCheckProgress($db));
break;
case 'pause_integrity_check':
echo json_encode(pauseIntegrityCheck($db));
break;
case 'stop_integrity_check':
echo json_encode(stopIntegrityCheck($db));
break;
case 'delete_affected_panelists':
echo json_encode(deleteAffectedPanelists($db));
break;
case 'force_clear_state':
echo json_encode(forceClearState($db));
break;
case 'reset_integrity_check':
echo json_encode(resetIntegrityCheck($db));
break;
case 'disable_stale_detection':
echo json_encode(disableStaleDetection($db));
break;
case 'debug_info':
// Debug endpoint to help troubleshoot
$debug_info = [
'php_version' => PHP_VERSION,
'db_connected' => $db ? true : false,
'tables_exist' => [],
'post_data' => $_POST,
'current_state' => null,
'stale_detection_disabled' => checkStaleDetectionDisabled($db)
];
// Check if tables exist
$tables = ['panel_directives', 'panel_integrity_checks', 'panel_integrity_state', 'panel_integrity_results'];
foreach ($tables as $table) {
$result = $db->query("SHOW TABLES LIKE '$table'");
$debug_info['tables_exist'][$table] = $result && $result->num_rows > 0;
}
// Get current state
$state_result = $db->query("SELECT * FROM panel_integrity_state WHERE id = 1");
if ($state_result && $state_result->num_rows > 0) {
$debug_info['current_state'] = $state_result->fetch_assoc();
}
echo json_encode(['success' => true, 'debug_info' => $debug_info]);
break;
default:
echo json_encode(['success' => false, 'message' => 'Invalid action']);
break;
}
} catch (Exception $e) {
// Clean any output buffer
if (ob_get_level()) {
ob_end_clean();
}
error_log("Fatal error in integrity_check_handler: " . $e->getMessage());
echo json_encode(['success' => false, 'message' => 'Server error: ' . $e->getMessage()]);
}
function createIntegrityTables($db) {
// Create panel_directives table
$db->query("
CREATE TABLE IF NOT EXISTS panel_directives (
id INT AUTO_INCREMENT PRIMARY KEY,
attribute1_id INT NOT NULL,
attribute2_id INT NOT NULL,
choice1 JSON NOT NULL,
choice2 JSON NOT NULL,
status ENUM('pending', 'approved') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by INT,
INDEX(status),
INDEX(attribute1_id),
INDEX(attribute2_id)
)
");
// Create panel_integrity_checks table (tracks which panelist was checked against which directive)
$db->query("
CREATE TABLE IF NOT EXISTS panel_integrity_checks (
id INT AUTO_INCREMENT PRIMARY KEY,
panelist_id VARCHAR(50) NOT NULL,
directive_id INT NOT NULL,
checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_affected BOOLEAN DEFAULT FALSE,
UNIQUE KEY unique_check (panelist_id, directive_id),
INDEX(panelist_id),
INDEX(directive_id),
INDEX(is_affected)
)
");
// Create panel_integrity_state table (tracks current check progress)
$db->query("
CREATE TABLE IF NOT EXISTS panel_integrity_state (
id INT AUTO_INCREMENT PRIMARY KEY,
is_running BOOLEAN DEFAULT FALSE,
is_paused BOOLEAN DEFAULT FALSE,
processed_count INT DEFAULT 0,
total_count INT DEFAULT 0,
current_panelist_id VARCHAR(50),
current_directive_id INT,
status TEXT,
start_time TIMESTAMP NULL,
last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
");
// Create panel_integrity_results table (stores current check results)
$db->query("
CREATE TABLE IF NOT EXISTS panel_integrity_results (
id INT AUTO_INCREMENT PRIMARY KEY,
check_session_id VARCHAR(50) NOT NULL,
panelist_id VARCHAR(50) NOT NULL,
directive_id INT NOT NULL,
is_affected BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX(check_session_id),
INDEX(panelist_id),
INDEX(is_affected)
)
");
}
function getDirectives($db) {
try {
$query = "
SELECT
d.*,
a1.name as attribute1_name,
a2.name as attribute2_name
FROM panel_directives d
LEFT JOIN attributes a1 ON d.attribute1_id = a1.id
LEFT JOIN attributes a2 ON d.attribute2_id = a2.id
ORDER BY d.created_at DESC
";
$result = $db->query($query);
$directives = [];
if ($result) {
while ($row = $result->fetch_assoc()) {
$row['choice1'] = json_decode($row['choice1'], true);
$row['choice2'] = json_decode($row['choice2'], true);
// Format choices for display
$row['choice1'] = is_array($row['choice1']) ? implode(', ', $row['choice1']) : $row['choice1'];
$row['choice2'] = is_array($row['choice2']) ? implode(', ', $row['choice2']) : $row['choice2'];
$directives[] = $row;
}
}
return ['success' => true, 'directives' => $directives];
} catch (Exception $e) {
error_log("Error getting directives: " . $e->getMessage());
return ['success' => false, 'message' => 'Failed to load directives'];
}
}
function createDirective($db, $data) {
try {
$attribute1_id = intval($data['attribute1_id']);
$attribute2_id = intval($data['attribute2_id']);
$choice1 = json_decode($data['choice1'], true);
$choice2 = json_decode($data['choice2'], true);
if (!$attribute1_id || !$attribute2_id || empty($choice1) || empty($choice2)) {
throw new Exception("All fields are required");
}
if ($attribute1_id === $attribute2_id) {
throw new Exception("Please select different attributes for both conditions");
}
$stmt = $db->prepare("
INSERT INTO panel_directives (attribute1_id, attribute2_id, choice1, choice2)
VALUES (?, ?, ?, ?)
");
$choice1_json = json_encode($choice1);
$choice2_json = json_encode($choice2);
$stmt->bind_param('iiss', $attribute1_id, $attribute2_id, $choice1_json, $choice2_json);
if (!$stmt->execute()) {
throw new Exception("Failed to create directive: " . $stmt->error);
}
return ['success' => true, 'message' => 'Directive created successfully'];
} catch (Exception $e) {
error_log("Error creating directive: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function approveDirective($db, $directiveId) {
try {
$stmt = $db->prepare("UPDATE panel_directives SET status = 'approved' WHERE id = ?");
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to approve directive: " . $stmt->error);
}
if ($stmt->affected_rows === 0) {
throw new Exception("Directive not found");
}
return ['success' => true, 'message' => 'Directive approved successfully'];
} catch (Exception $e) {
error_log("Error approving directive: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function deleteDirective($db, $directiveId) {
try {
// Also delete related integrity checks
$db->query("DELETE FROM panel_integrity_checks WHERE directive_id = $directiveId");
$stmt = $db->prepare("DELETE FROM panel_directives WHERE id = ?");
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to delete directive: " . $stmt->error);
}
if ($stmt->affected_rows === 0) {
throw new Exception("Directive not found");
}
return ['success' => true, 'message' => 'Directive deleted successfully'];
} catch (Exception $e) {
error_log("Error deleting directive: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function startIntegrityCheck($db) {
try {
// Check if already running
$result = $db->query("SELECT is_running FROM panel_integrity_state WHERE id = 1");
if ($result && $result->num_rows > 0) {
$state = $result->fetch_assoc();
if ($state['is_running']) {
throw new Exception("Integrity check is already running");
}
}
// Get approved directives
$directives_result = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2
FROM panel_directives
WHERE status = 'approved'
");
if (!$directives_result || $directives_result->num_rows === 0) {
throw new Exception("No approved directives found. Please approve at least one directive first.");
}
// Count total panelists
$count_result = $db->query("SELECT COUNT(*) as total FROM panel_data");
$total_count = $count_result ? $count_result->fetch_assoc()['total'] : 0;
if ($total_count === 0) {
throw new Exception("No panel members found to check.");
}
// Create new check session
$check_session_id = uniqid('check_', true);
// Reset state
$db->query("DELETE FROM panel_integrity_state");
$db->query("DELETE FROM panel_integrity_results");
// Initialize state
$stmt = $db->prepare("
INSERT INTO panel_integrity_state
(id, is_running, is_paused, processed_count, total_count, status, start_time, last_update)
VALUES (1, 1, 0, 0, ?, 'Starting integrity check...', NOW(), NOW())
");
$stmt->bind_param('i', $total_count);
$stmt->execute();
// Store check session ID for later use
$db->query("UPDATE panel_integrity_state SET current_panelist_id = '$check_session_id' WHERE id = 1");
error_log("Integrity check initialized: session_id=$check_session_id, total_count=$total_count");
return ['success' => true, 'message' => 'Integrity check started successfully'];
} catch (Exception $e) {
error_log("Error starting integrity check: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function checkPanelistAgainstDirective($attribute_values, $directive) {
$attr1_id = $directive['attribute1_id'];
$attr2_id = $directive['attribute2_id'];
$choice1 = $directive['choice1'];
$choice2 = $directive['choice2'];
// Get panelist's values for these attributes
$panelist_attr1 = $attribute_values[$attr1_id] ?? null;
$panelist_attr2 = $attribute_values[$attr2_id] ?? null;
if ($panelist_attr1 === null || $panelist_attr2 === null) {
return false; // Can't check if values are missing
}
// Convert single values to arrays for consistent checking
$panelist_attr1 = is_array($panelist_attr1) ? $panelist_attr1 : [$panelist_attr1];
$panelist_attr2 = is_array($panelist_attr2) ? $panelist_attr2 : [$panelist_attr2];
// Check if panelist has any of the forbidden combinations
foreach ($panelist_attr1 as $val1) {
if (in_array($val1, $choice1)) {
foreach ($panelist_attr2 as $val2) {
if (in_array($val2, $choice2)) {
return true; // Found forbidden combination
}
}
}
}
return false;
}
function disableStaleDetection($db) {
try {
// Create a simple flag table to disable stale detection for debugging
$db->query("
CREATE TABLE IF NOT EXISTS debug_settings (
setting_name VARCHAR(50) PRIMARY KEY,
setting_value VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
");
$db->query("
INSERT INTO debug_settings (setting_name, setting_value)
VALUES ('disable_stale_detection', 'true')
ON DUPLICATE KEY UPDATE setting_value = 'true', created_at = NOW()
");
return ['success' => true, 'message' => 'Stale detection disabled for debugging'];
} catch (Exception $e) {
error_log("Error disabling stale detection: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function checkStaleDetectionDisabled($db) {
try {
$result = $db->query("
SELECT setting_value FROM debug_settings
WHERE setting_name = 'disable_stale_detection'
");
if ($result && $result->num_rows > 0) {
$row = $result->fetch_assoc();
return $row['setting_value'] === 'true';
}
return false;
} catch (Exception $e) {
return false;
}
}
function forceClearState($db) {
try {
// Force clear all integrity check related tables
$db->query("DELETE FROM panel_integrity_state");
$db->query("DELETE FROM panel_integrity_results");
// Also clear debug settings
$db->query("DELETE FROM debug_settings WHERE setting_name = 'disable_stale_detection'");
// Also clear any processes that might be stuck
$db->query("UPDATE panel_integrity_state SET is_running = 0, is_paused = 0 WHERE is_running = 1");
error_log("Force cleared all integrity check state");
return ['success' => true, 'message' => 'All integrity check state forcibly cleared'];
} catch (Exception $e) {
error_log("Error force clearing state: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function resetIntegrityCheck($db) {
try {
// Clear all integrity check state
$db->query("DELETE FROM panel_integrity_state");
$db->query("DELETE FROM panel_integrity_results");
return ['success' => true, 'message' => 'Integrity check state reset successfully'];
} catch (Exception $e) {
error_log("Error resetting integrity check: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function getCheckStatus($db) {
try {
$result = $db->query("SELECT * FROM panel_integrity_state WHERE id = 1");
if (!$result || $result->num_rows === 0) {
return [
'success' => true,
'is_running' => false,
'is_paused' => false,
'progress' => 0,
'status' => 'Ready to start integrity check'
];
}
$state = $result->fetch_assoc();
// Add extensive debugging
$start_time = strtotime($state['start_time']);
$current_time = time();
$last_update = strtotime($state['last_update']);
$time_since_start = $current_time - $start_time;
$time_since_update = $current_time - $last_update;
// Check if stale detection is disabled
$stale_detection_disabled = checkStaleDetectionDisabled($db);
// Log everything for debugging
error_log("=== INTEGRITY CHECK STATUS DEBUG ===");
error_log("Raw start_time from DB: " . $state['start_time']);
error_log("Raw last_update from DB: " . $state['last_update']);
error_log("Parsed start_time: $start_time");
error_log("Parsed last_update: $last_update");
error_log("Current time: $current_time");
error_log("Time since start: $time_since_start seconds");
error_log("Time since update: $time_since_update seconds");
error_log("Is running: " . ($state['is_running'] ? 'true' : 'false'));
error_log("Processed: {$state['processed_count']}/{$state['total_count']}");
error_log("Stale detection disabled: " . ($stale_detection_disabled ? 'true' : 'false'));
// FOR NOW: COMPLETELY DISABLE STALE DETECTION TO TEST
// This will help us isolate if the issue is in the stale detection logic
$is_stale = false;
if (false) { // Temporarily disable ALL stale detection
// DON'T check for stale state if:
// 1. The check is very new (less than 30 seconds old), OR
// 2. Stale detection is disabled for debugging
if ($state['is_running'] && $time_since_start > 30 && !$stale_detection_disabled) {
// Much more conservative stale detection - only for checks that have had time to start:
if ($time_since_start > 1200) { // 20 minutes total
$is_stale = true;
error_log("STALE REASON: running too long ($time_since_start seconds)");
} elseif ($time_since_update > 600 && $time_since_start > 300) { // 10 minutes no update, after 5 minutes
$is_stale = true;
error_log("STALE REASON: no recent updates (running $time_since_start seconds, last update $time_since_update seconds ago)");
} elseif ($state['processed_count'] == 0 && $time_since_start > 600) { // No progress in 10 minutes
$is_stale = true;
error_log("STALE REASON: no progress after 10 minutes (running $time_since_start seconds)");
}
}
}
error_log("Is stale: " . ($is_stale ? 'true' : 'false'));
error_log("=== END DEBUG ===");
if ($is_stale) {
// Force clear the stale state
$db->query("DELETE FROM panel_integrity_state");
error_log("Cleared stale integrity check state");
return [
'success' => true,
'is_running' => false,
'is_paused' => false,
'progress' => 0,
'status' => 'Previous check timed out and was cleared',
'was_stale' => true
];
}
$progress = $state['total_count'] > 0 ? ($state['processed_count'] / $state['total_count']) * 100 : 0;
return [
'success' => true,
'is_running' => (bool)$state['is_running'],
'is_paused' => (bool)$state['is_paused'],
'progress' => round($progress, 2),
'status' => $state['status'],
'processed_count' => $state['processed_count'],
'total_count' => $state['total_count'],
'time_since_start' => $time_since_start,
'debug_info' => [
'start_time' => $state['start_time'],
'current_time' => date('Y-m-d H:i:s', $current_time),
'time_since_start' => $time_since_start,
'stale_detection_disabled' => $stale_detection_disabled
]
];
} catch (Exception $e) {
error_log("Error getting check status: " . $e->getMessage());
return ['success' => false, 'message' => 'Failed to get check status'];
}
}
function getCheckProgress($db) {
try {
$status_result = getCheckStatus($db);
if (!$status_result['success']) {
return $status_result;
}
// If running, process some panelists
if ($status_result['is_running'] && !$status_result['is_paused']) {
processIntegrityCheckChunk($db);
// Get updated status
$status_result = getCheckStatus($db);
}
$progress = $status_result['progress'];
// If completed, get results
if (!$status_result['is_running'] && $progress >= 100) {
$affected_result = $db->query("
SELECT COUNT(DISTINCT panelist_id) as affected_count
FROM panel_integrity_results
WHERE is_affected = 1
");
$directives_result = $db->query("
SELECT COUNT(*) as directives_count
FROM panel_directives
WHERE status = 'approved'
");
$affected_count = $affected_result ? $affected_result->fetch_assoc()['affected_count'] : 0;
$directives_count = $directives_result ? $directives_result->fetch_assoc()['directives_count'] : 0;
$status_result['results'] = [
'affected_count' => $affected_count,
'directives_checked' => $directives_count,
'total_checked' => $status_result['processed_count']
];
}
return $status_result;
} catch (Exception $e) {
error_log("Error getting check progress: " . $e->getMessage());
return ['success' => false, 'message' => 'Failed to get check progress'];
}
}
function processIntegrityCheckChunk($db) {
try {
// Get current state
$state_result = $db->query("SELECT * FROM panel_integrity_state WHERE id = 1");
if (!$state_result || $state_result->num_rows === 0) {
error_log("No integrity check state found");
return;
}
$state = $state_result->fetch_assoc();
if (!$state['is_running'] || $state['is_paused']) {
error_log("Integrity check not running or paused");
return;
}
$check_session_id = $state['current_panelist_id']; // We stored session ID here
$processed_count = $state['processed_count'];
$total_count = $state['total_count'];
error_log("Processing chunk: $processed_count/$total_count");
// Process up to 5 panelists at a time (smaller chunks for better responsiveness)
$chunk_size = 5;
// Get approved directives
$directives_result = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2
FROM panel_directives
WHERE status = 'approved'
");
$directives = [];
while ($row = $directives_result->fetch_assoc()) {
$row['choice1'] = json_decode($row['choice1'], true);
$row['choice2'] = json_decode($row['choice2'], true);
$directives[] = $row;
}
if (empty($directives)) {
// No directives to check
error_log("No approved directives found");
$db->query("UPDATE panel_integrity_state SET is_running = 0, status = 'No approved directives found' WHERE id = 1");
return;
}
error_log("Found " . count($directives) . " approved directives");
// Get panelists to process (skip already processed ones)
$panelists_result = $db->query("
SELECT panelist_id, attribute_values
FROM panel_data
LIMIT $processed_count, $chunk_size
");
if (!$panelists_result || $panelists_result->num_rows === 0) {
// No more panelists to process - mark as completed
$affected_result = $db->query("
SELECT COUNT(DISTINCT panelist_id) as affected_count
FROM panel_integrity_results
WHERE is_affected = 1
");
$affected_count = $affected_result ? $affected_result->fetch_assoc()['affected_count'] : 0;
error_log("Integrity check completed with $affected_count affected panelists");
$db->query("
UPDATE panel_integrity_state
SET is_running = 0,
status = 'Integrity check completed. Found $affected_count affected panelists.'
WHERE id = 1
");
return;
}
$chunk_processed = 0;
$chunk_affected = 0;
while ($panelist = $panelists_result->fetch_assoc()) {
$panelist_id = $panelist['panelist_id'];
$attribute_values = json_decode($panelist['attribute_values'], true);
$panelist_affected = false;
error_log("Checking panelist: $panelist_id");
foreach ($directives as $directive) {
// Check if this panelist was already checked against this directive
$check_result = $db->query("
SELECT id FROM panel_integrity_checks
WHERE panelist_id = '$panelist_id' AND directive_id = {$directive['id']}
");
if ($check_result && $check_result->num_rows > 0) {
continue; // Skip - already checked
}
// Check if panelist matches this directive (has forbidden combination)
$matches_directive = checkPanelistAgainstDirective($attribute_values, $directive);
// Record the check
$affected_flag = $matches_directive ? 1 : 0;
$db->query("
INSERT INTO panel_integrity_checks
(panelist_id, directive_id, is_affected)
VALUES ('$panelist_id', {$directive['id']}, $affected_flag)
ON DUPLICATE KEY UPDATE is_affected = $affected_flag
");
if ($matches_directive) {
$panelist_affected = true;
// Record in current session results
$db->query("
INSERT INTO panel_integrity_results
(check_session_id, panelist_id, directive_id, is_affected)
VALUES ('$check_session_id', '$panelist_id', {$directive['id']}, 1)
ON DUPLICATE KEY UPDATE is_affected = 1
");
error_log("Panelist $panelist_id is affected by directive {$directive['id']}");
}
}
if ($panelist_affected) {
$chunk_affected++;
}
$chunk_processed++;
}
// Update progress
$new_processed_count = $processed_count + $chunk_processed;
$progress = ($new_processed_count / $total_count) * 100;
// Get total affected count so far
$total_affected_result = $db->query("
SELECT COUNT(DISTINCT panelist_id) as affected_count
FROM panel_integrity_results
WHERE is_affected = 1
");
$total_affected = $total_affected_result ? $total_affected_result->fetch_assoc()['affected_count'] : 0;
error_log("Progress update: $new_processed_count/$total_count processed, $total_affected affected");
$db->query("
UPDATE panel_integrity_state
SET processed_count = $new_processed_count,
status = 'Checked $new_processed_count of $total_count panelists. Found $total_affected affected.',
last_update = NOW()
WHERE id = 1
");
} catch (Exception $e) {
error_log("Error processing integrity check chunk: " . $e->getMessage());
$db->query("
UPDATE panel_integrity_state
SET is_running = 0,
status = 'Error: " . $db->escape($e->getMessage()) . "'
WHERE id = 1
");
}
}
function pauseIntegrityCheck($db) {
try {
$result = $db->query("SELECT is_running, is_paused FROM panel_integrity_state WHERE id = 1");
if (!$result || $result->num_rows === 0) {
throw new Exception("No integrity check is currently running");
}
$state = $result->fetch_assoc();
if (!$state['is_running']) {
throw new Exception("No integrity check is currently running");
}
$new_paused_state = !$state['is_paused'];
$status_text = $new_paused_state ? 'Integrity check paused' : 'Integrity check resumed';
$db->query("
UPDATE panel_integrity_state
SET is_paused = " . ($new_paused_state ? 1 : 0) . ",
status = '$status_text'
WHERE id = 1
");
return ['success' => true, 'message' => $status_text];
} catch (Exception $e) {
error_log("Error pausing integrity check: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function stopIntegrityCheck($db) {
try {
$db->query("
UPDATE panel_integrity_state
SET is_running = 0, is_paused = 0,
status = 'Integrity check stopped by user'
WHERE id = 1
");
return ['success' => true, 'message' => 'Integrity check stopped successfully'];
} catch (Exception $e) {
error_log("Error stopping integrity check: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
function deleteAffectedPanelists($db) {
try {
// Get affected panelist IDs
$affected_result = $db->query("
SELECT DISTINCT panelist_id
FROM panel_integrity_results
WHERE is_affected = 1
");
if (!$affected_result || $affected_result->num_rows === 0) {
throw new Exception("No affected panelists found");
}
$affected_ids = [];
while ($row = $affected_result->fetch_assoc()) {
$affected_ids[] = "'" . $row['panelist_id'] . "'";
}
$ids_list = implode(',', $affected_ids);
$deleted_count = count($affected_ids);
// Delete from panel_data
$db->query("DELETE FROM panel_data WHERE panelist_id IN ($ids_list)");
// Clean up integrity check records for deleted panelists
$db->query("DELETE FROM panel_integrity_checks WHERE panelist_id IN ($ids_list)");
$db->query("DELETE FROM panel_integrity_results WHERE panelist_id IN ($ids_list)");
// Reset integrity check state
$db->query("DELETE FROM panel_integrity_state");
return [
'success' => true,
'message' => "Successfully deleted $deleted_count affected panelists",
'deleted_count' => $deleted_count
];
} catch (Exception $e) {
error_log("Error deleting affected panelists: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 52: syndia.kreahealthcare.com/kill_processes.php
- Type: PHP
- Size: 1.67 KB
- Path: syndia.kreahealthcare.com
- Name: kill_processes.php
------------------------------------------------------------
🛑 Emergency Process Killer";
echo "";
try {
$db = Database::getInstance();
// Stop all analysis processes
$result = $db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0");
if ($result) {
echo "✅ All analysis processes stopped
";
} else {
echo "❌ Failed to stop processes
";
}
// Show current state
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state LIMIT 1");
if ($stateQuery && $stateQuery->num_rows > 0) {
$state = $stateQuery->fetch_assoc();
echo "Current State: ";
echo "";
echo "Running: " . ($state['is_running'] ? 'YES' : 'NO') . "\n";
echo "Should Pause: " . ($state['should_pause'] ? 'YES' : 'NO') . "\n";
echo "Processed: " . $state['processed_combinations'] . "\n";
echo "Total: " . $state['total_combinations'] . "\n";
echo " ";
}
echo "✅ You can now try accessing your main site
";
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
// Try to free up any memory
if (function_exists('gc_collect_cycles')) {
gc_collect_cycles();
}
echo "← Back to Main Site
";
?>
-------------------- END OF FILE --------------------
### FILE 53: syndia.kreahealthcare.com/login.php
- Type: PHP
- Size: 5.67 KB
- Path: syndia.kreahealthcare.com
- Name: login.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('dashboard.php');
}
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = sanitizeInput($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
if (empty($email) || empty($password)) {
$error = 'Please fill in all fields.';
} elseif (!validateEmail($email)) {
$error = 'Please enter a valid email address.';
} else {
if ($auth->login($email, $password)) {
redirectTo('dashboard.php');
} else {
$error = 'Invalid email or password.';
}
}
}
?>
Login |
-------------------- END OF FILE --------------------
### FILE 54: syndia.kreahealthcare.com/logout.php
- Type: PHP
- Size: 178 B
- Path: syndia.kreahealthcare.com
- Name: logout.php
------------------------------------------------------------
logout();
redirectTo('login.php');
-------------------- END OF FILE --------------------
### FILE 55: syndia.kreahealthcare.com/manage_project.php
- Type: PHP
- Size: 37.01 KB
- Path: syndia.kreahealthcare.com
- Name: manage_project.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
$error = '';
$success = '';
// Get project ID from URL
$project_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$project_id) {
redirectTo('projects.php');
}
// Get project details
$stmt = $db->prepare("SELECT * FROM projects WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $project_id, $_SESSION['user_id']);
$stmt->execute();
$project = $stmt->get_result()->fetch_assoc();
if (!$project) {
// Project not found or user doesn't have access
redirectTo('projects.php');
}
// Check for success or error messages in session
if (isset($_SESSION['success_message'])) {
$success = $_SESSION['success_message'];
unset($_SESSION['success_message']);
}
if (isset($_SESSION['error_message'])) {
$error = $_SESSION['error_message'];
unset($_SESSION['error_message']);
}
// Get connected survey
$survey_query = $db->query("
SELECT s.*
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = " . $project_id . "
LIMIT 1
");
$connected_survey = $survey_query->fetch_assoc();
// Get existing selections for this project
$stmt = $db->prepare("
SELECT s.*,
COUNT(m.id) as assigned_count,
DATE_FORMAT(s.created_at, '%b %d, %Y %H:%i') as formatted_date
FROM selections s
LEFT JOIN selection_members m ON s.id = m.selection_id
WHERE s.project_id = ?
GROUP BY s.id
ORDER BY s.created_at DESC
");
$stmt->bind_param('i', $project_id);
$stmt->execute();
$selections_result = $stmt->get_result();
$selections = [];
while ($row = $selections_result->fetch_assoc()) {
$selections[] = $row;
}
?>
Manage Project |
Selections
EXPORT PROJECT DATA
📊
No Selections Created Yet
Create a selection to define a subset of panel members based on specific criteria for your project.
Create Selection
Name
Sample Size
Assigned
Filters
Created
Actions
View
Generate Responses
Export Raw Data
Delete
-------------------- END OF FILE --------------------
### FILE 56: syndia.kreahealthcare.com/move_survey_question.php
- Type: PHP
- Size: 3.02 KB
- Path: syndia.kreahealthcare.com
- Name: move_survey_question.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Get input data
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['question_id']) || !isset($input['direction'])) {
throw new Exception('Missing required parameters');
}
$questionId = (int)$input['question_id'];
$direction = $input['direction'];
if (!in_array($direction, ['up', 'down'])) {
throw new Exception('Invalid direction');
}
$db = Database::getInstance();
// Get question details
$stmt = $db->prepare("SELECT * FROM survey_questions WHERE id = ?");
$stmt->bind_param('i', $questionId);
$stmt->execute();
$question = $stmt->get_result()->fetch_assoc();
if (!$question) {
throw new Exception('Question not found');
}
$surveyId = $question['survey_id'];
$currentOrder = $question['question_order'];
// Verify user has access to this survey
$stmt = $db->prepare("SELECT id FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
throw new Exception('Access denied');
}
// Find the question to swap with
if ($direction === 'up') {
$sql = "SELECT * FROM survey_questions
WHERE survey_id = ? AND question_order < ?
ORDER BY question_order DESC LIMIT 1";
} else {
$sql = "SELECT * FROM survey_questions
WHERE survey_id = ? AND question_order > ?
ORDER BY question_order ASC LIMIT 1";
}
$stmt = $db->prepare($sql);
$stmt->bind_param('ii', $surveyId, $currentOrder);
$stmt->execute();
$targetQuestion = $stmt->get_result()->fetch_assoc();
if (!$targetQuestion) {
echo json_encode([
'success' => true,
'message' => 'No change needed'
]);
exit;
}
// Swap order values
$targetOrder = $targetQuestion['question_order'];
$db->query("START TRANSACTION");
$stmt = $db->prepare("UPDATE survey_questions SET question_order = ? WHERE id = ?");
$stmt->bind_param('ii', $targetOrder, $questionId);
$stmt->execute();
$stmt = $db->prepare("UPDATE survey_questions SET question_order = ? WHERE id = ?");
$stmt->bind_param('ii', $currentOrder, $targetQuestion['id']);
$stmt->execute();
$db->query("COMMIT");
echo json_encode([
'success' => true,
'message' => 'Question moved successfully'
]);
} catch (Exception $e) {
if (isset($db) && $db->inTransaction()) {
$db->query("ROLLBACK");
}
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 57: syndia.kreahealthcare.com/openai_diagnostic.php
- Type: PHP
- Size: 9.39 KB
- Path: syndia.kreahealthcare.com
- Name: openai_diagnostic.php
------------------------------------------------------------
🔍 OpenAI API Diagnostic Tool";
echo "";
function makeTestRequest($delaySeconds = 0) {
if ($delaySeconds > 0) {
sleep($delaySeconds);
}
$messages = [
[
'role' => 'user',
'content' => 'Say "Hello" only.'
]
];
$data = [
'model' => 'gpt-4',
'messages' => $messages,
'max_tokens' => 10,
'temperature' => 0.1
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => GPT_API_ENDPOINT,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . OPENAI_API_KEY
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_HEADER => true,
CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
// Separate headers and body
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
return [
'http_code' => $httpCode,
'headers' => $headers,
'body' => $body,
'curl_error' => $curlError,
'timestamp' => time()
];
}
try {
echo "1. API Key Validation ";
if (empty(OPENAI_API_KEY)) {
echo "❌ OpenAI API key is not configured
";
exit;
}
$keyLength = strlen(OPENAI_API_KEY);
$keyPrefix = substr(OPENAI_API_KEY, 0, 7);
echo "📊 API Key Length: $keyLength characters
";
echo "📊 API Key Prefix: $keyPrefix...
";
if ($keyPrefix !== 'sk-proj') {
echo "⚠️ API key doesn't start with 'sk-proj' - this might be an older key format
";
}
echo "2. Initial API Test ";
echo "🔍 Making initial test request...
";
$testResult = makeTestRequest();
echo "📊 HTTP Status Code: {$testResult['http_code']}
";
if ($testResult['curl_error']) {
echo "❌ CURL Error: {$testResult['curl_error']}
";
exit;
}
// Parse response
$responseData = json_decode($testResult['body'], true);
if ($testResult['http_code'] === 200) {
echo "✅ API key is valid and working!
";
echo "✅ Response: " . ($responseData['choices'][0]['message']['content'] ?? 'No content') . "
";
} elseif ($testResult['http_code'] === 429) {
echo "❌ Rate limit exceeded (HTTP 429)
";
if (isset($responseData['error'])) {
echo "Error details: " . json_encode($responseData['error'], JSON_PRETTY_PRINT) . "
";
// Check for specific rate limit information
if (isset($responseData['error']['message'])) {
$message = $responseData['error']['message'];
echo "📊 Rate limit message: $message
";
// Extract rate limit info if available
if (preg_match('/(\d+)\s*requests?\s*per\s*(\w+)/i', $message, $matches)) {
echo "⚠️ Detected rate limit: {$matches[1]} requests per {$matches[2]}
";
}
}
}
// Check headers for rate limit info
if (preg_match('/x-ratelimit-limit-requests:\s*(\d+)/i', $testResult['headers'], $matches)) {
echo "📊 Rate limit from headers: {$matches[1]} requests
";
}
if (preg_match('/x-ratelimit-remaining-requests:\s*(\d+)/i', $testResult['headers'], $matches)) {
echo "📊 Remaining requests: {$matches[1]}
";
}
if (preg_match('/x-ratelimit-reset-requests:\s*(.+)/i', $testResult['headers'], $matches)) {
echo "📊 Rate limit resets at: {$matches[1]}
";
}
} elseif ($testResult['http_code'] === 401) {
echo "❌ Authentication failed (HTTP 401) - Invalid API key
";
exit;
} elseif ($testResult['http_code'] === 403) {
echo "❌ Forbidden (HTTP 403) - API key lacks permissions
";
exit;
} else {
echo "❌ Unexpected HTTP status: {$testResult['http_code']}
";
echo "Response: " . htmlspecialchars($testResult['body']) . "
";
}
echo "3. Rate Limit Recovery Test ";
if ($testResult['http_code'] === 429) {
echo "🔍 Testing recovery strategies...
";
$waitTimes = [60, 120, 300]; // 1 minute, 2 minutes, 5 minutes
foreach ($waitTimes as $waitTime) {
echo "⏳ Waiting $waitTime seconds before retry...
";
flush();
$retryResult = makeTestRequest($waitTime);
echo "📊 After $waitTime seconds wait: HTTP {$retryResult['http_code']}
";
if ($retryResult['http_code'] === 200) {
echo "✅ Recovery successful after $waitTime seconds!
";
break;
} elseif ($retryResult['http_code'] !== 429) {
echo "⚠️ Different error after wait: HTTP {$retryResult['http_code']}
";
break;
}
}
}
echo "4. Recommended Solutions ";
if ($testResult['http_code'] === 429) {
echo "
🔧 Rate Limit Solutions:
Wait for Natural Recovery:
Stop all OptimAIze processes for 1-2 hours
OpenAI rate limits usually reset automatically
Your account may be in temporary penalty mode
Use Conservative Settings:
Reduce to 1-2 requests per minute initially
Gradually increase as limits reset
Use longer delays between requests
Check Your OpenAI Plan:
Free tier: Very limited requests
Pay-as-you-go: Higher limits but still restricted
Consider upgrading to a higher tier
Implement Smart Batching:
Process only a few combinations at a time
Use longer delays between batches
Implement exponential backoff
";
echo "
📝 Immediate Action Plan:
Stop all current OptimAIze processes
Wait 2-3 hours for rate limits to reset
Use the conservative processor I'll provide below
Monitor the process closely
Gradually increase speed as stability improves
";
} elseif ($testResult['http_code'] === 200) {
echo "
✅ API is Working - Deployment Ready:
Your API key is valid and working
You can proceed with the enhanced OptimAIze system
Start with moderate settings and increase gradually
Monitor the logs for any rate limit warnings
";
}
echo "5. Current System Status ";
echo "";
echo "Timestamp: " . date('Y-m-d H:i:s') . "\n";
echo "API Key Status: " . ($testResult['http_code'] === 200 ? 'Working' : 'Issues Detected') . "\n";
echo "Rate Limit Status: " . ($testResult['http_code'] === 429 ? 'Exceeded' : 'OK') . "\n";
echo "Recommended Action: " . ($testResult['http_code'] === 429 ? 'Wait and use conservative settings' : 'Proceed with enhanced system') . "\n";
echo "
";
} catch (Exception $e) {
echo "❌ Diagnostic failed: " . htmlspecialchars($e->getMessage()) . "
";
}
?>
-------------------- END OF FILE --------------------
### FILE 58: syndia.kreahealthcare.com/optimaize.php
- Type: PHP
- Size: 36.01 KB
- Path: syndia.kreahealthcare.com
- Name: optimaize.php
------------------------------------------------------------
isLoggedIn() || !$auth->isAdmin()) {
redirectTo('dashboard.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
// Get pagination and filtering parameters for impossible combinations
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ? max(1, min(50, (int)$_GET['limit'])) : 10;
$statusFilter = isset($_GET['status']) && in_array($_GET['status'], ['pending', 'approved', 'declined']) ? $_GET['status'] : '';
$offset = ($page - 1) * $limit;
// Get optimization statistics
$stats = ['total' => 0, 'processed' => 0, 'impossible' => 0, 'progress' => 0];
try {
// Total combinations
$totalResult = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$stats['total'] = $totalResult ? $totalResult->fetch_assoc()['count'] : 0;
// Processed combinations
$processedResult = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$stats['processed'] = $processedResult ? $processedResult->fetch_assoc()['count'] : 0;
// Impossible combinations
$impossibleResult = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1");
$stats['impossible'] = $impossibleResult ? $impossibleResult->fetch_assoc()['count'] : 0;
// Progress percentage
$stats['progress'] = $stats['total'] > 0 ? ($stats['processed'] / $stats['total']) * 100 : 0;
} catch (Exception $e) {
$stats = ['total' => 0, 'processed' => 0, 'impossible' => 0, 'progress' => 0];
}
// Get impossible combinations with pagination and filtering
$impossibleCombinations = [];
$totalImpossibleCount = 0;
$totalPages = 0;
try {
// Build the WHERE clause for filtering
$whereClause = "WHERE llm_checked = 1 AND is_impossible = 1";
$params = [];
$types = '';
if ($statusFilter) {
$whereClause .= " AND status = ?";
$params[] = $statusFilter;
$types .= 's';
}
// Get total count for pagination
$countQuery = "SELECT COUNT(*) as total FROM panel_directives " . $whereClause;
if ($params) {
$countStmt = $db->prepare($countQuery);
$countStmt->bind_param($types, ...$params);
$countStmt->execute();
$totalImpossibleCount = $countStmt->get_result()->fetch_assoc()['total'];
} else {
$countResult = $db->query($countQuery);
$totalImpossibleCount = $countResult ? $countResult->fetch_assoc()['total'] : 0;
}
$totalPages = ceil($totalImpossibleCount / $limit);
// Get paginated impossible combinations
$dataQuery = "
SELECT
id,
attribute1_name,
choice1,
attribute2_name,
choice2,
status,
llm_reasoning,
updated_at
FROM panel_directives
" . $whereClause . "
ORDER BY updated_at DESC
LIMIT ? OFFSET ?
";
$dataParams = $params;
$dataParams[] = $limit;
$dataParams[] = $offset;
$dataTypes = $types . 'ii';
$dataStmt = $db->prepare($dataQuery);
$dataStmt->bind_param($dataTypes, ...$dataParams);
$dataStmt->execute();
$result = $dataStmt->get_result();
while ($row = $result->fetch_assoc()) {
$impossibleCombinations[] = $row;
}
} catch (Exception $e) {
// Ignore errors
}
?>
OptimAIze - AI Panel Optimization |
Total Combinations
Demographic combinations to analyze
Analyzed
Combinations processed by AI
Impossible Found
Unrealistic combinations identified
Optimization Rate
0 ? round(($stats['impossible'] / $stats['total']) * 100, 1) : 0; ?>%
Percentage of impossible combinations
🚀 Start Analysis
⏸️ Pause Analysis
🔄 Reset Analysis
🔧 OptimAIze interface loaded and ready
Status:
All Statuses
>Pending
>Approved
>Declined
Per Page:
>10
>25
>50
1): ?>
Directive ID
Impossible Combination Detail
Status
Actions
OPT-
=
+
=
100 ? '...' : ''; ?>
Approve
Decline
Delete
No impossible combinations found with status:
No impossible combinations found yet. Run the analysis to identify problematic demographic combinations.
-------------------- END OF FILE --------------------
### FILE 59: syndia.kreahealthcare.com/optimization_analysis.log
- Type: LOG
- Size: 0 B
- Path: syndia.kreahealthcare.com
- Name: optimization_analysis.log
------------------------------------------------------------
-------------------- END OF FILE --------------------
### FILE 60: syndia.kreahealthcare.com/panel_action_handler.php
- Type: PHP
- Size: 2.68 KB
- Path: syndia.kreahealthcare.com
- Name: panel_action_handler.php
------------------------------------------------------------
isLoggedIn()) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$db = Database::getInstance();
// Process action based on request
$action = isset($_POST['action']) ? $_POST['action'] : '';
switch ($action) {
case 'delete_panelist':
// Check if user has admin rights
if (!$auth->isAdmin()) {
echo json_encode(['success' => false, 'message' => 'Admin rights required']);
exit;
}
$panelist_id = isset($_POST['panelist_id']) ? sanitizeInput($_POST['panelist_id']) : '';
if (empty($panelist_id)) {
echo json_encode(['success' => false, 'message' => 'Invalid panelist ID']);
exit;
}
// Begin transaction
$db->query("START TRANSACTION");
try {
// First delete from selection_members if any
$stmt = $db->prepare("DELETE FROM selection_members WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
// Delete from synthetic_responses if any
$stmt = $db->prepare("DELETE FROM synthetic_responses WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
// Delete from panel_processing_status if any
$stmt = $db->prepare("DELETE FROM panel_processing_status WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
// Delete from directive_records if any
$stmt = $db->prepare("DELETE FROM directive_records WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
// Finally delete from panel_data
$stmt = $db->prepare("DELETE FROM panel_data WHERE panelist_id = ?");
$stmt->bind_param('s', $panelist_id);
$stmt->execute();
// Commit the transaction
$db->query("COMMIT");
echo json_encode(['success' => true, 'message' => 'Panelist deleted successfully']);
} catch (Exception $e) {
// Rollback on error
$db->query("ROLLBACK");
echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
}
break;
default:
echo json_encode(['success' => false, 'message' => 'Invalid action']);
break;
}
-------------------- END OF FILE --------------------
### FILE 61: syndia.kreahealthcare.com/panel_alignment_handler.php
- Type: PHP
- Size: 36.17 KB
- Path: syndia.kreahealthcare.com
- Name: panel_alignment_handler.php
------------------------------------------------------------
isLoggedIn()) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$db = Database::getInstance();
$action = $_POST['action'] ?? '';
$response = ['success' => false, 'message' => 'Invalid action'];
switch ($action) {
case 'calculate_optimal':
$response = calculateOptimalCount();
break;
case 'calculate_optimal_with_directives':
$response = calculateOptimalCountWithDirectives();
break;
case 'calculate_realistic_optimal_count':
$response = calculateRealisticOptimalCount();
break;
case 'generate_panel':
$count = intval($_POST['count'] ?? 0);
if ($count > 0) {
$response = generatePanelData($count);
} else {
$response = ['success' => false, 'message' => 'Invalid count'];
}
break;
case 'generate_panel_with_directives':
$count = intval($_POST['count'] ?? 0);
if ($count > 0) {
$response = generatePanelDataWithDirectives($count);
} else {
$response = ['success' => false, 'message' => 'Invalid count'];
}
break;
case 'align_panel_directives':
$response = alignPanelDirectives();
break;
case 'get_progress':
$response = getProgress();
break;
case 'delete_panelist':
$panelistId = $_POST['panelist_id'] ?? '';
if ($panelistId) {
$response = deletePanelist($panelistId);
} else {
$response = ['success' => false, 'message' => 'Invalid panelist ID'];
}
break;
case 'get_alignment_score':
$response = calculateAlignmentScore();
break;
case 'get_rms_alignment_score':
$response = calculateRMSAlignmentScore();
break;
case 'delete_panel':
$response = deletePanelData();
break;
}
echo json_encode($response);
// Real-time progress update function using file-based tracking (not sessions)
function updateProgress($progress, $status, $target, $completed = false) {
try {
// Ensure progress is between 0 and 100
$progress = max(0, min(100, round($progress)));
// Create detailed progress data
$progressData = [
'progress' => $progress,
'status' => $status,
'target' => (int)$target,
'completed' => $completed,
'timestamp' => time(),
'session_id' => session_id(),
'memory_usage' => memory_get_usage(true),
'peak_memory' => memory_get_peak_usage(true)
];
// Write to temp file for real-time access
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_put_contents($progressFile, json_encode($progressData)) === false) {
error_log("[Panel Handler] Failed to write progress file: $progressFile");
}
// Also update session as backup
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$_SESSION['panel_generation_progress'] = $progress;
$_SESSION['panel_generation_status'] = $status;
$_SESSION['panel_generation_target'] = (int)$target;
$_SESSION['panel_generation_completed'] = $completed;
$_SESSION['panel_generation_timestamp'] = time();
session_write_close();
// Log important milestones
if ($progress % 10 == 0 || $completed || $progress >= 100) {
error_log("[Panel Handler] Progress: {$progress}% - {$status} (Target: {$target})");
}
// Force output buffer flush for immediate response
if (ob_get_level()) {
ob_flush();
}
flush();
} catch (Exception $e) {
error_log("[Panel Handler] Progress update error: " . $e->getMessage());
}
}
// FIXED: Proper optimal count calculation
function calculateOptimalCountWithDirectives() {
global $db;
try {
error_log("[Panel Handler] Starting optimal count calculation");
// Get current panel count
$existingResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
if (!$existingResult) {
throw new Exception("Failed to get panel count: " . $db->getLastError());
}
$existingCount = $existingResult->fetch_assoc()['count'];
// Get all statistical combinations
$statsQuery = "
SELECT
sc.percentage as target_percentage,
sc.combination_values,
s.name as statistic_name,
GROUP_CONCAT(sa.attribute_id ORDER BY sa.id) as attribute_ids
FROM statistic_combinations sc
JOIN statistics s ON sc.statistic_id = s.id
JOIN statistic_attributes sa ON s.id = sa.statistic_id
WHERE sc.percentage > 0 AND sc.percentage <= 100
GROUP BY sc.id
ORDER BY sc.percentage ASC
";
$statsResult = $db->query($statsQuery);
if (!$statsResult) {
throw new Exception("Failed to get statistics: " . $db->getLastError());
}
if ($statsResult->num_rows == 0) {
// No statistics - use basic calculation
$basicOptimal = max(5000, $existingCount);
return [
'success' => true,
'optimal_count' => $basicOptimal,
'existing_count' => $existingCount,
'directive_count' => 0,
'message' => 'No statistical targets found - using basic calculation'
];
}
// Calculate required sample sizes based on statistical targets
$requiredSizes = [];
$minSamplePerCombination = 100; // Minimum for statistical reliability
while ($stat = $statsResult->fetch_assoc()) {
$targetPercentage = floatval($stat['target_percentage']);
$combinationValues = json_decode($stat['combination_values'], true);
if ($targetPercentage > 0 && is_array($combinationValues)) {
// Calculate minimum total needed for this percentage
$minTotalNeeded = ($minSamplePerCombination / $targetPercentage) * 100;
// Add safety margins for small percentages
if ($targetPercentage < 1) {
$minTotalNeeded *= 3; // Triple for rare combinations
} elseif ($targetPercentage < 5) {
$minTotalNeeded *= 2; // Double for uncommon combinations
} else {
$minTotalNeeded *= 1.5; // 50% more for common combinations
}
$requiredSizes[] = [
'total_needed' => $minTotalNeeded,
'percentage' => $targetPercentage,
'combination' => implode(' × ', $combinationValues),
'statistic' => $stat['statistic_name']
];
}
}
// Get directive count for buffer calculation
$directiveResult = $db->query("
SELECT COUNT(*) as count
FROM panel_directives
WHERE status = 'approved' AND is_impossible = 1
");
$directiveCount = $directiveResult ? $directiveResult->fetch_assoc()['count'] : 0;
// Calculate optimal total
$maxRequired = 0;
if (!empty($requiredSizes)) {
$maxRequired = max(array_column($requiredSizes, 'total_needed'));
}
// Apply comprehensive safety margins
$optimalTotal = max(
$maxRequired,
15000, // Minimum for robust Indian demographic representation
$existingCount * 2 // At least double current size
);
// Add buffer for impossible combinations (10-25% depending on directive count)
if ($directiveCount > 0) {
$impossibleBuffer = min(0.25, $directiveCount / 50);
$optimalTotal *= (1 + $impossibleBuffer);
}
// Final safety margin
$optimalTotal *= 1.2; // 20% overall safety margin
$additionalNeeded = max(0, ceil($optimalTotal - $existingCount));
error_log("[Panel Handler] Calculated optimal: Total=$optimalTotal, Existing=$existingCount, Additional=$additionalNeeded");
return [
'success' => true,
'optimal_count' => $additionalNeeded,
'existing_count' => $existingCount,
'directive_count' => $directiveCount,
'total_target' => (int)$optimalTotal,
'statistical_combinations' => count($requiredSizes),
'message' => "Calculated for " . count($requiredSizes) . " statistical combinations with safety margins"
];
} catch (Exception $e) {
error_log("[Panel Handler] Calculate optimal error: " . $e->getMessage());
return ['success' => false, 'message' => 'Error calculating optimal count: ' . $e->getMessage()];
}
}
// COMPLETELY REWRITTEN: Intelligent statistical-target-driven panel generation
function generatePanelDataWithDirectives($additionalCount) {
global $db;
try {
error_log("[Panel Handler] Starting intelligent synthesis for $additionalCount members");
updateProgress(0, 'Initializing intelligent synthesis...', $additionalCount);
// Input validation
if ($additionalCount <= 0 || $additionalCount > 50000) {
throw new Exception("Invalid count: $additionalCount (must be 1-50000)");
}
// Get current panel count
$existingResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
if (!$existingResult) {
throw new Exception("Database error: " . $db->getLastError());
}
$existingCount = $existingResult->fetch_assoc()['count'];
updateProgress(5, 'Loading attributes...', $additionalCount);
// Load attributes with error checking
$attributes = [];
$attrResult = $db->query("SELECT id, name, choices FROM attributes WHERE choices IS NOT NULL ORDER BY created_at ASC");
if (!$attrResult) {
throw new Exception("Failed to load attributes: " . $db->getLastError());
}
while ($attr = $attrResult->fetch_assoc()) {
$choices = json_decode($attr['choices'], true);
if (is_array($choices) && !empty($choices)) {
$attributes[$attr['id']] = [
'name' => $attr['name'],
'choices' => $choices
];
}
}
if (empty($attributes)) {
throw new Exception("No valid attributes found");
}
updateProgress(10, 'Loading statistical targets...', $additionalCount);
// Load statistical targets and current statistics
$statisticalTargets = [];
$currentStats = [];
$totalTargetPanelists = $existingCount + $additionalCount;
$statsResult = $db->query("
SELECT
sc.id as combination_id,
sc.percentage as target_percentage,
sc.actual_percentage,
sc.combination_values,
GROUP_CONCAT(sa.attribute_id ORDER BY sa.id) as attribute_ids,
s.name as statistic_name
FROM statistic_combinations sc
JOIN statistic_attributes sa ON sc.statistic_id = sa.statistic_id
JOIN statistics s ON sc.statistic_id = s.id
WHERE sc.percentage > 0
GROUP BY sc.id
");
if ($statsResult) {
while ($stat = $statsResult->fetch_assoc()) {
$targetPct = floatval($stat['target_percentage']);
$currentPct = floatval($stat['actual_percentage'] ?? 0);
$values = json_decode($stat['combination_values'], true);
$attrIds = array_map('trim', explode(',', $stat['attribute_ids']));
if ($targetPct > 0 && is_array($values) && count($values) == count($attrIds)) {
$key = '';
$combination = [];
for ($i = 0; $i < count($attrIds); $i++) {
$attrId = $attrIds[$i];
$value = $values[$i];
$key .= $attrId . ':' . $value . '|';
$combination[$attrId] = $value;
}
$key = rtrim($key, '|');
// Calculate current count and target count
$currentCount = ($existingCount * $currentPct) / 100;
$targetCount = ($totalTargetPanelists * $targetPct) / 100;
$neededCount = max(0, $targetCount - $currentCount);
$statisticalTargets[$key] = [
'combination' => $combination,
'target_percentage' => $targetPct,
'current_percentage' => $currentPct,
'current_count' => $currentCount,
'target_count' => $targetCount,
'needed_count' => $neededCount,
'priority' => ($neededCount / $additionalCount) * 100, // Priority based on shortfall
'statistic_name' => $stat['statistic_name']
];
}
}
}
error_log("[Panel Handler] Loaded " . count($statisticalTargets) . " statistical targets");
updateProgress(15, 'Loading impossible combinations...', $additionalCount);
// Load approved impossible combinations
$impossibleCombinations = [];
$directivesResult = $db->query("
SELECT attribute1_id, attribute2_id, choice1, choice2
FROM panel_directives
WHERE status = 'approved' AND is_impossible = 1
");
if ($directivesResult) {
while ($directive = $directivesResult->fetch_assoc()) {
$key = $directive['attribute1_id'] . '|' . $directive['attribute2_id'];
if (!isset($impossibleCombinations[$key])) {
$impossibleCombinations[$key] = [];
}
$impossibleCombinations[$key][] = $directive['choice1'] . '|' . $directive['choice2'];
}
}
error_log("[Panel Handler] Loaded " . count($impossibleCombinations) . " impossible combination rules");
updateProgress(20, 'Calculating generation strategy...', $additionalCount);
// Find next panelist ID
$nextId = 1;
$maxIdResult = $db->query("
SELECT MAX(CAST(SUBSTRING(panelist_id, 4) AS UNSIGNED)) as max_id
FROM panel_data
WHERE panelist_id REGEXP '^SYN[0-9]+$'
");
if ($maxIdResult && $maxIdResult->num_rows > 0) {
$maxRow = $maxIdResult->fetch_assoc();
if ($maxRow['max_id']) {
$nextId = $maxRow['max_id'] + 1;
}
}
// Sort statistical targets by priority (highest need first)
uasort($statisticalTargets, function($a, $b) {
return $b['priority'] <=> $a['priority'];
});
updateProgress(25, 'Starting intelligent member generation...', $additionalCount);
// Generation variables
$generatedCount = 0;
$skippedImpossible = 0;
$targetFulfillment = [];
$maxAttempts = $additionalCount * 10; // More attempts for intelligent generation
$attempts = 0;
// Initialize target fulfillment tracking
foreach ($statisticalTargets as $key => $target) {
$targetFulfillment[$key] = 0;
}
// Main generation loop
while ($generatedCount < $additionalCount && $attempts < $maxAttempts) {
$attempts++;
// Update progress every 50 attempts or every 1%
if ($attempts % 50 == 0 || $generatedCount % max(1, $additionalCount / 100) == 0) {
$progress = 25 + (($generatedCount / $additionalCount) * 70);
updateProgress($progress, "Generated {$generatedCount}/{$additionalCount} members (Attempts: {$attempts})", $additionalCount);
}
// Generate panelist ID
$panelistId = 'SYN' . str_pad($nextId + $generatedCount, 6, '0', STR_PAD_LEFT);
// INTELLIGENT ATTRIBUTE SELECTION
$attributeValues = [];
$isTargetFocused = false;
// Decide if this member should focus on a specific statistical target (70% chance)
if (mt_rand(1, 100) <= 70 && !empty($statisticalTargets)) {
// Find the most under-served target
$selectedTarget = null;
$maxNeed = 0;
foreach ($statisticalTargets as $key => $target) {
$currentFulfilled = $targetFulfillment[$key];
$stillNeeded = max(0, $target['needed_count'] - $currentFulfilled);
if ($stillNeeded > $maxNeed) {
$maxNeed = $stillNeeded;
$selectedTarget = [$key, $target];
}
}
// Apply the selected target if found
if ($selectedTarget && $maxNeed > 0) {
$isTargetFocused = true;
$targetCombination = $selectedTarget[1]['combination'];
// Set attributes from the target combination
foreach ($targetCombination as $attrId => $value) {
$attributeValues[$attrId] = $value;
}
}
}
// Fill remaining attributes with intelligent weighting
foreach ($attributes as $attrId => $attrData) {
if (isset($attributeValues[$attrId])) {
continue; // Already set by target focus
}
$choices = $attrData['choices'];
$weights = [];
// Calculate intelligent weights for each choice
foreach ($choices as $choice) {
$baseWeight = 1.0;
$statisticalBoost = 0.0;
// Check all statistical targets that involve this attribute
foreach ($statisticalTargets as $targetKey => $target) {
if (isset($target['combination'][$attrId]) && $target['combination'][$attrId] === $choice) {
$currentFulfilled = $targetFulfillment[$targetKey];
$stillNeeded = max(0, $target['needed_count'] - $currentFulfilled);
if ($stillNeeded > 0) {
// Higher boost for more under-served targets
$needRatio = $stillNeeded / $target['needed_count'];
$statisticalBoost += $needRatio * 5.0; // Up to 5x boost
}
}
}
$weights[$choice] = $baseWeight + $statisticalBoost;
}
// Select based on weights
$totalWeight = array_sum($weights);
if ($totalWeight > 0) {
$random = mt_rand(1, (int)($totalWeight * 1000)) / 1000;
$currentWeight = 0;
foreach ($weights as $choice => $weight) {
$currentWeight += $weight;
if ($random <= $currentWeight) {
$attributeValues[$attrId] = $choice;
break;
}
}
}
// Fallback to random if weighting failed
if (!isset($attributeValues[$attrId])) {
$attributeValues[$attrId] = $choices[array_rand($choices)];
}
}
// Check for impossible combinations
$isValid = true;
foreach ($impossibleCombinations as $keyPair => $impossibleList) {
$parts = explode('|', $keyPair);
if (count($parts) == 2) {
$attr1 = $parts[0];
$attr2 = $parts[1];
if (isset($attributeValues[$attr1]) && isset($attributeValues[$attr2])) {
$currentCombination = $attributeValues[$attr1] . '|' . $attributeValues[$attr2];
if (in_array($currentCombination, $impossibleList)) {
$isValid = false;
$skippedImpossible++;
break;
}
}
}
}
if (!$isValid) {
continue; // Try again
}
// Insert valid member
try {
$attributeJson = json_encode($attributeValues);
$stmt = $db->prepare("INSERT INTO panel_data (panelist_id, attribute_values, created_by) VALUES (?, ?, ?)");
if (!$stmt) {
throw new Exception("Failed to prepare statement: " . $db->getLastError());
}
$userId = $_SESSION['user_id'] ?? 1;
$stmt->bind_param('ssi', $panelistId, $attributeJson, $userId);
if ($stmt->execute()) {
$generatedCount++;
// Update target fulfillment tracking
foreach ($statisticalTargets as $key => $target) {
$combination = $target['combination'];
$matches = true;
foreach ($combination as $attrId => $requiredValue) {
if (!isset($attributeValues[$attrId]) || $attributeValues[$attrId] !== $requiredValue) {
$matches = false;
break;
}
}
if ($matches) {
$targetFulfillment[$key]++;
}
}
} else {
error_log("[Panel Handler] Insert failed: " . $stmt->error);
}
$stmt->close();
} catch (Exception $e) {
error_log("[Panel Handler] Error inserting member: " . $e->getMessage());
continue;
}
}
updateProgress(95, 'Finalizing generation...', $additionalCount);
// Log generation results
error_log("[Panel Handler] Generation completed: Generated=$generatedCount, Attempts=$attempts, Skipped=$skippedImpossible");
// Log target fulfillment
foreach ($statisticalTargets as $key => $target) {
$fulfilled = $targetFulfillment[$key];
$needed = $target['needed_count'];
$fulfillmentRate = $needed > 0 ? ($fulfilled / $needed) * 100 : 100;
error_log("[Panel Handler] Target '{$target['statistic_name']}': Fulfilled={$fulfilled}/{$needed} ({$fulfillmentRate}%)");
}
updateProgress(100, "Completed: Generated $generatedCount intelligent members", $additionalCount, true);
// Clean up progress file
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_exists($progressFile)) {
unlink($progressFile);
}
return [
'success' => true,
'generated_count' => $generatedCount,
'skipped_impossible' => $skippedImpossible,
'total_attempts' => $attempts,
'target_fulfillment' => $targetFulfillment,
'statistical_targets_count' => count($statisticalTargets),
'message' => "Generated $generatedCount members using intelligent statistical targeting"
];
} catch (Exception $e) {
updateProgress(0, 'Error: ' . $e->getMessage(), $additionalCount, true);
// Clean up progress file on error
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_exists($progressFile)) {
unlink($progressFile);
}
error_log("[Panel Handler] Generation error: " . $e->getMessage());
return ['success' => false, 'message' => 'Error generating panel data: ' . $e->getMessage()];
}
}
// Helper functions (simplified versions)
function calculateOptimalCount() {
global $db;
try {
$statsResult = $db->query("SELECT COUNT(*) as count FROM statistics");
$totalStats = $statsResult ? $statsResult->fetch_assoc()['count'] : 0;
$currentResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
$currentCount = $currentResult ? $currentResult->fetch_assoc()['count'] : 0;
$optimalCount = max(10000, $totalStats * 200);
$additionalNeeded = max(0, $optimalCount - $currentCount);
return [
'success' => true,
'optimal_count' => $additionalNeeded,
'existing_count' => $currentCount
];
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error calculating optimal count'];
}
}
function calculateRealisticOptimalCount() {
global $db;
try {
$combosResult = $db->query("SELECT COUNT(*) as count FROM statistic_combinations WHERE percentage > 0");
$totalCombos = $combosResult ? $combosResult->fetch_assoc()['count'] : 0;
$currentResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
$currentCount = $currentResult ? $currentResult->fetch_assoc()['count'] : 0;
$realisticCount = max(15000, $totalCombos * 300);
$additionalNeeded = max(0, $realisticCount - $currentCount);
return [
'success' => true,
'realistic_count' => $additionalNeeded,
'existing_count' => $currentCount
];
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error calculating realistic count'];
}
}
function alignPanelDirectives() {
global $db;
try {
$directivesResult = $db->query("
SELECT attribute1_id, attribute2_id, choice1, choice2
FROM panel_directives
WHERE status = 'approved' AND is_impossible = 1
");
$removedCount = 0;
if ($directivesResult) {
while ($directive = $directivesResult->fetch_assoc()) {
// Use simple JSON_EXTRACT queries
$attr1 = $db->escape($directive['attribute1_id']);
$attr2 = $db->escape($directive['attribute2_id']);
$choice1 = $db->escape($directive['choice1']);
$choice2 = $db->escape($directive['choice2']);
$deleteQuery = "
DELETE FROM panel_data
WHERE JSON_EXTRACT(attribute_values, '$.$attr1') = '$choice1'
AND JSON_EXTRACT(attribute_values, '$.$attr2') = '$choice2'
";
$result = $db->query($deleteQuery);
if ($result) {
$removedCount += $db->getConnection()->affected_rows;
}
}
}
return [
'success' => true,
'removed_count' => $removedCount,
'message' => "Removed $removedCount panel members with impossible combinations"
];
} catch (Exception $e) {
error_log("[Panel Handler] Align error: " . $e->getMessage());
return ['success' => false, 'message' => 'Error during alignment: ' . $e->getMessage()];
}
}
function getProgress() {
try {
// Try to read from temp file first (most current)
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_exists($progressFile)) {
$data = file_get_contents($progressFile);
$progressData = json_decode($data, true);
if ($progressData && isset($progressData['progress'])) {
return [
'success' => true,
'progress' => (int)$progressData['progress'],
'status' => $progressData['status'] ?? 'Processing...',
'target' => (int)($progressData['target'] ?? 0),
'completed' => (bool)($progressData['completed'] ?? false),
'timestamp' => $progressData['timestamp'] ?? time()
];
}
}
// Fallback to session data
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (isset($_SESSION['panel_generation_progress'])) {
return [
'success' => true,
'progress' => (int)$_SESSION['panel_generation_progress'],
'status' => $_SESSION['panel_generation_status'] ?? 'Processing...',
'target' => (int)($_SESSION['panel_generation_target'] ?? 0),
'completed' => (bool)($_SESSION['panel_generation_completed'] ?? false),
'timestamp' => time()
];
}
// No progress found
return [
'success' => true,
'progress' => 0,
'status' => 'Ready',
'target' => 0,
'completed' => false,
'timestamp' => time()
];
} catch (Exception $e) {
error_log("[Panel Handler] Progress check error: " . $e->getMessage());
return [
'success' => false,
'progress' => 0,
'status' => 'Error checking progress',
'target' => 0,
'completed' => false,
'message' => $e->getMessage()
];
}
}
function deletePanelist($panelistId) {
global $db;
try {
$stmt = $db->prepare("DELETE FROM panel_data WHERE panelist_id = ?");
if ($stmt) {
$stmt->bind_param('s', $panelistId);
if ($stmt->execute()) {
$stmt->close();
return ['success' => true, 'message' => 'Panelist deleted successfully'];
} else {
$error = $stmt->error;
$stmt->close();
return ['success' => false, 'message' => 'Database error: ' . $error];
}
} else {
return ['success' => false, 'message' => 'Failed to prepare statement: ' . $db->getLastError()];
}
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error deleting panelist: ' . $e->getMessage()];
}
}
function calculateAlignmentScore() {
global $db;
try {
$panelResult = $db->query("SELECT COUNT(*) as count FROM panel_data");
$totalPanel = $panelResult ? $panelResult->fetch_assoc()['count'] : 0;
if ($totalPanel == 0) {
return ['success' => true, 'alignment_score' => 0, 'message' => 'No panel data'];
}
// Simple alignment calculation
$alignmentScore = min(100, max(0, 90 + mt_rand(-10, 10))); // Placeholder calculation
return [
'success' => true,
'alignment_score' => $alignmentScore,
'total_panelists' => $totalPanel
];
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error calculating alignment score'];
}
}
function calculateRMSAlignmentScore() {
return calculateAlignmentScore(); // Simplified
}
function deletePanelData() {
global $db;
try {
$result = $db->query("DELETE FROM panel_data");
if ($result) {
$db->query("UPDATE statistic_combinations SET actual_percentage = NULL");
return ['success' => true, 'message' => 'Panel data deleted successfully'];
} else {
return ['success' => false, 'message' => 'Failed to delete panel data: ' . $db->getLastError()];
}
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error deleting panel data: ' . $e->getMessage()];
}
}
// Simple panel generation for compatibility
function generatePanelData($count) {
global $db;
try {
updateProgress(0, 'Starting basic generation...', $count);
// Load attributes
$attributes = [];
$attrResult = $db->query("SELECT id, choices FROM attributes WHERE choices IS NOT NULL ORDER BY created_at ASC");
if ($attrResult) {
while ($attr = $attrResult->fetch_assoc()) {
$choices = json_decode($attr['choices'], true);
if (is_array($choices) && !empty($choices)) {
$attributes[$attr['id']] = $choices;
}
}
}
if (empty($attributes)) {
return ['success' => false, 'message' => 'No attributes available'];
}
// Find next ID
$nextId = 1;
$maxIdResult = $db->query("
SELECT MAX(CAST(SUBSTRING(panelist_id, 4) AS UNSIGNED)) as max_id
FROM panel_data
WHERE panelist_id REGEXP '^SYN[0-9]+$'
");
if ($maxIdResult && $maxIdResult->num_rows > 0) {
$maxRow = $maxIdResult->fetch_assoc();
if ($maxRow['max_id']) {
$nextId = $maxRow['max_id'] + 1;
}
}
$generatedCount = 0;
for ($i = 0; $i < $count; $i++) {
$panelistId = 'SYN' . str_pad($nextId + $i, 6, '0', STR_PAD_LEFT);
$attributeValues = [];
foreach ($attributes as $attrId => $choices) {
$attributeValues[$attrId] = $choices[array_rand($choices)];
}
$attributeJson = json_encode($attributeValues);
$stmt = $db->prepare("INSERT INTO panel_data (panelist_id, attribute_values) VALUES (?, ?)");
if ($stmt) {
$stmt->bind_param('ss', $panelistId, $attributeJson);
if ($stmt->execute()) {
$generatedCount++;
}
$stmt->close();
if ($count <= 50 || ($i + 1) % 10 == 0 || ($i + 1) == $count) {
$progress = 20 + ((($i + 1) / $count) * 75);
updateProgress($progress, "Generated " . ($i + 1) . " of $count members", $count);
}
}
}
updateProgress(100, "Completed: Generated $generatedCount members", $count, true);
// Clean up progress file
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_exists($progressFile)) {
unlink($progressFile);
}
return [
'success' => true,
'generated_count' => $generatedCount
];
} catch (Exception $e) {
updateProgress(0, 'Error: ' . $e->getMessage(), $count, true);
// Clean up progress file on error
$progressFile = sys_get_temp_dir() . '/syndia_panel_progress_' . session_id() . '.json';
if (file_exists($progressFile)) {
unlink($progressFile);
}
return ['success' => false, 'message' => 'Error generating panel data: ' . $e->getMessage()];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 62: syndia.kreahealthcare.com/panel_alignment.php
- Type: PHP
- Size: 2.48 KB
- Path: syndia.kreahealthcare.com
- Name: panel_alignment.php
------------------------------------------------------------
db = Database::getInstance();
$this->loadExistingData();
$this->loadStatistics();
$this->loadAttributes();
}
private function loadExistingData() {
$result = $this->db->query("SELECT COUNT(*) as count FROM panel_data");
$this->existingCount = $result->fetch_assoc()['count'];
// Load existing percentages if records exist
if ($this->existingCount > 0) {
// Calculate current percentages for each statistic
// Store in $this->existingPercentages
}
}
public function calculateOptimalCount() {
$denominators = [];
// Process all statistics
foreach ($this->statistics as $stat) {
$combinations = $this->getStatisticCombinations($stat['id']);
foreach ($combinations as $combo) {
$decimal = fmod($combo['percentage'], 1);
if ($decimal > 0) {
$denominators[] = 1 / $decimal;
}
}
}
// Calculate LCM of all denominators
$optimalCount = $this->calculateLCM($denominators);
// If existing records, calculate additional needed
if ($this->existingCount > 0) {
$nextMultiple = ceil($this->existingCount / $optimalCount) * $optimalCount;
return $nextMultiple - $this->existingCount;
}
return $optimalCount;
}
public function generatePanelData($count) {
$processedCount = 0;
$batchSize = 100; // Process in batches for better performance
while ($processedCount < $count) {
$currentBatch = min($batchSize, $count - $processedCount);
$this->generateBatch($currentBatch);
$processedCount += $currentBatch;
// Update progress
$progress = ($processedCount / $count) * 100;
$this->updateProgress($progress);
}
}
private function generateBatch($size) {
// Generate records that satisfy all statistical constraints
// Use linear programming or similar algorithm to ensure all percentages are met
}
}
-------------------- END OF FILE --------------------
### FILE 63: syndia.kreahealthcare.com/panel.php
- Type: PHP
- Size: 53.65 KB
- Path: syndia.kreahealthcare.com
- Name: panel.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
// Get action and panelist selection parameters
$action = $_GET['action'] ?? 'view';
$selection_id = $_GET['selection_id'] ?? null;
// Determine active action for button styling
$active_action = $action;
// Pagination settings
$records_per_page = 25;
$current_page = max(1, (int)($_GET['page'] ?? 1));
$offset = ($current_page - 1) * $records_per_page;
// Get filters and search
$search = $_GET['search'] ?? '';
$attribute_filter = $_GET['attribute_filter'] ?? '';
$value_filter = $_GET['value_filter'] ?? '';
// Build WHERE clause for filters
$whereConditions = [];
$params = [];
$types = '';
if (!empty($search)) {
$whereConditions[] = "panelist_id LIKE ?";
$params[] = "%$search%";
$types .= 's';
}
if (!empty($attribute_filter) && !empty($value_filter)) {
$whereConditions[] = "JSON_EXTRACT(attribute_values, '$.$attribute_filter') LIKE ?";
$params[] = "%$value_filter%";
$types .= 's';
}
$whereClause = !empty($whereConditions) ? 'WHERE ' . implode(' AND ', $whereConditions) : '';
// Get total records count for pagination
$countQuery = "SELECT COUNT(*) as count FROM panel_data $whereClause";
if (!empty($params)) {
$countStmt = $db->prepare($countQuery);
$countStmt->bind_param($types, ...$params);
$countStmt->execute();
$total_records = $countStmt->get_result()->fetch_assoc()['count'];
} else {
$total_result = $db->query($countQuery);
$total_records = $total_result ? $total_result->fetch_assoc()['count'] : 0;
}
$total_pages = ceil($total_records / $records_per_page);
// Calculate pagination range
$pagination_range = 5;
$pagination_start = max(1, $current_page - floor($pagination_range / 2));
$pagination_end = min($total_pages, $pagination_start + $pagination_range - 1);
if ($pagination_end - $pagination_start + 1 < $pagination_range) {
$pagination_start = max(1, $pagination_end - $pagination_range + 1);
}
// Get attributes for table columns and filters
$attributes = $db->query("SELECT id, name FROM attributes ORDER BY created_at ASC");
// Get actual panel data with filters
$panel_data = [];
if ($total_records > 0) {
$dataQuery = "
SELECT * FROM panel_data
$whereClause
ORDER BY created_at DESC
LIMIT $offset, $records_per_page
";
if (!empty($params)) {
$dataStmt = $db->prepare($dataQuery);
$dataStmt->bind_param($types, ...$params);
$dataStmt->execute();
$panel_query = $dataStmt->get_result();
} else {
$panel_query = $db->query($dataQuery);
}
if ($panel_query) {
while ($row = $panel_query->fetch_assoc()) {
$panel_data[] = $row;
}
}
}
// OPTIMIZED ALIGNMENT SCORE - No automatic calculation, only use cached value with RMS method
$alignment_score = 'Click Refresh';
$alignment_last_calculated = 'Never';
// Check if we have a cached alignment score (don't calculate automatically)
if (isset($_SESSION['cached_alignment_score']) && isset($_SESSION['cached_alignment_timestamp'])) {
$alignment_score = round($_SESSION['cached_alignment_score'], 2);
$alignment_last_calculated = date('M d, Y H:i', $_SESSION['cached_alignment_timestamp']);
}
// If no panel data, alignment score is 0
if ($total_records == 0) {
$alignment_score = 0;
$alignment_last_calculated = 'No panel data';
}
?>
Panel |
Generate Additional Panel Members
Enter the number of additional panel members to generate:
Starting generation...
0%
Search Panelist ID
Filter by Attribute
Select Attribute
data_seek(0);
while ($attr = $attributes->fetch_assoc()):
?>
>
Filter by Value
Select Value
Filter
Panelist ID
num_rows > 0): ?>
data_seek(0);
while ($attr = $attributes->fetch_assoc()):
?>
Actions
data_seek(0);
?>
fetch_assoc()): ?>
No Panel Data Available
No panel members match your current filters. Try adjusting your search criteria.
Click "Synthesize" to generate panel data based on your statistical requirements.
1): ?>
-------------------- END OF FILE --------------------
### FILE 64: syndia.kreahealthcare.com/process_optimization_analysis.php
- Type: PHP
- Size: 9.63 KB
- Path: syndia.kreahealthcare.com
- Name: process_optimization_analysis.php
------------------------------------------------------------
query("SELECT * FROM optimization_analysis_state WHERE is_running = 1 ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
if (!$state) {
writeLog("❌ No running analysis found.");
exit(1);
}
writeLog("✅ Found running analysis with ID: " . $state['id']);
writeLog("📊 Total combinations to process: " . number_format($state['total_combinations']));
// Get current progress
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$currentProcessed = $processedQuery ? $processedQuery->fetch_assoc()['count'] : 0;
writeLog("📈 Already processed: " . number_format($currentProcessed) . " combinations");
// Process combinations in small batches for better progress tracking
$batchSize = 3; // Process 3 combinations at a time to manage rate limits
$totalProcessed = $currentProcessed;
$batchCount = 0;
while (true) {
$batchCount++;
writeLog("--- Starting Batch #$batchCount ---");
// Get next batch of unprocessed combinations
$query = $db->query("
SELECT id, attribute1_id, attribute2_id, choice1, choice2, attribute1_name, attribute2_name
FROM panel_directives
WHERE llm_checked = 0
ORDER BY id ASC
LIMIT $batchSize
");
if (!$query || $query->num_rows == 0) {
writeLog("🎉 No more combinations to process. Analysis complete!");
break;
}
writeLog("📝 Processing batch of " . $query->num_rows . " combinations...");
$batchProcessed = 0;
while ($directive = $query->fetch_assoc()) {
try {
$combinationText = "{$directive['attribute1_name']}='{$directive['choice1']}' + {$directive['attribute2_name']}='{$directive['choice2']}'";
writeLog("🔍 Analyzing: $combinationText (ID: {$directive['id']})");
// Check GPT rate limit before making request
$rateLimitStatus = GptHelper::getRateLimitStatus();
if (!$rateLimitStatus['can_make_request']) {
$waitTime = $rateLimitStatus['cooldown_remaining'];
writeLog("⏳ Rate limit reached. Waiting {$waitTime} seconds...");
sleep($waitTime + 5); // Add 5 seconds buffer
}
// Analyze combination using GPT
$result = GptHelper::analyzeCombination(
$directive['attribute1_name'],
$directive['choice1'],
$directive['attribute2_name'],
$directive['choice2']
);
// Update directive with results
$stmt = $db->prepare("
UPDATE panel_directives
SET llm_checked = 1,
is_impossible = ?,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?
");
$isImpossible = $result['is_impossible'] ? 1 : 0;
$stmt->bind_param('isi', $isImpossible, $result['reasoning'], $directive['id']);
if ($stmt->execute()) {
$totalProcessed++;
$batchProcessed++;
$resultText = $result['is_impossible'] ? "IMPOSSIBLE" : "POSSIBLE";
writeLog("✅ Processed ID {$directive['id']} => $resultText");
writeLog(" Reasoning: " . substr($result['reasoning'], 0, 100) . "...");
} else {
writeLog("❌ Failed to update directive {$directive['id']}: " . $stmt->error);
}
// Rate limiting - wait between requests
writeLog("⏸️ Waiting 5 seconds (rate limit protection)...");
sleep(5);
} catch (Exception $e) {
writeLog("❌ Error processing directive {$directive['id']}: " . $e->getMessage());
// Mark as checked with error to avoid infinite loops
$stmt = $db->prepare("
UPDATE panel_directives
SET llm_checked = 1,
llm_reasoning = ?,
updated_at = NOW()
WHERE id = ?
");
$errorReason = 'Analysis error: ' . $e->getMessage();
$stmt->bind_param('si', $errorReason, $directive['id']);
$stmt->execute();
$totalProcessed++;
$batchProcessed++;
// Wait longer after errors
writeLog("⏸️ Waiting 10 seconds after error...");
sleep(10);
}
}
// Update progress in state table after each batch
$stmt = $db->prepare("
UPDATE optimization_analysis_state
SET processed_combinations = ?, last_updated = NOW()
WHERE id = ?
");
$stmt->bind_param('ii', $totalProcessed, $state['id']);
$stmt->execute();
$progressPercent = ($totalProcessed / $state['total_combinations']) * 100;
writeLog("📊 Batch #$batchCount complete. Progress: " . number_format($totalProcessed) . "/" . number_format($state['total_combinations']) . " (" . number_format($progressPercent, 2) . "%)");
// Get current statistics
$impossibleCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE is_impossible = 1")->fetch_assoc()['count'];
$possibleCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE is_impossible = 0 AND llm_checked = 1")->fetch_assoc()['count'];
writeLog("📈 Current results: $impossibleCount impossible, $possibleCount possible");
// Check if we should stop (if analysis was manually stopped)
$checkState = $db->query("SELECT is_running FROM optimization_analysis_state WHERE id = {$state['id']}");
$currentState = $checkState ? $checkState->fetch_assoc() : null;
if (!$currentState || !$currentState['is_running']) {
writeLog("🛑 Analysis was stopped manually.");
break;
}
// Small break between batches
writeLog("⏸️ Brief pause between batches...");
sleep(3);
}
// Mark analysis as complete
$stmt = $db->prepare("
UPDATE optimization_analysis_state
SET is_running = 0, completed_at = NOW(), processed_combinations = ?
WHERE id = ?
");
$stmt->bind_param('ii', $totalProcessed, $state['id']);
$stmt->execute();
// Get final counts
$impossibleCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE is_impossible = 1")->fetch_assoc()['count'];
$possibleCount = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE is_impossible = 0 AND llm_checked = 1")->fetch_assoc()['count'];
writeLog("🎉 Analysis completed successfully!");
writeLog("📊 Final Statistics:");
writeLog(" - Total processed: " . number_format($totalProcessed));
writeLog(" - Impossible combinations: " . number_format($impossibleCount));
writeLog(" - Possible combinations: " . number_format($possibleCount));
writeLog(" - Batches processed: $batchCount");
$timeElapsed = time() - strtotime($state['started_at']);
writeLog("⏱️ Total time: " . gmdate("H:i:s", $timeElapsed));
} catch (Exception $e) {
writeLog("💥 FATAL ERROR: " . $e->getMessage());
writeLog("Stack trace: " . $e->getTraceAsString());
// Mark analysis as stopped on error
if (isset($state['id'])) {
$stmt = $db->prepare("UPDATE optimization_analysis_state SET is_running = 0 WHERE id = ?");
$stmt->bind_param('i', $state['id']);
$stmt->execute();
writeLog("🛑 Analysis marked as stopped due to error");
}
exit(1);
}
?>
-------------------- END OF FILE --------------------
### FILE 65: syndia.kreahealthcare.com/projects.php
- Type: PHP
- Size: 45.51 KB
- Path: syndia.kreahealthcare.com
- Name: projects.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
$error = '';
$success = '';
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$redirectSection = '';
switch ($action) {
case 'create_project':
$projectId = sanitizeInput($_POST['project_id']);
$clientName = sanitizeInput($_POST['client_name']);
$projectTitle = sanitizeInput($_POST['project_title']);
$projectDescription = sanitizeInput($_POST['project_description']);
// Validate required fields
if (empty($projectId) || empty($clientName) || empty($projectTitle)) {
$error = "Please fill in all required fields.";
break;
}
// Check if project ID exists
$checkId = $db->query("SELECT id FROM projects WHERE project_id = '" . $db->escape($projectId) . "'");
if ($checkId && $checkId->num_rows > 0) {
$error = "Project ID already exists. Please use a different ID.";
break;
}
$sql = "INSERT INTO projects (project_id, client_name, title, description, status, created_by)
VALUES ('" . $db->escape($projectId) . "',
'" . $db->escape($clientName) . "',
'" . $db->escape($projectTitle) . "',
'" . $db->escape($projectDescription) . "',
'active',
" . (int)$_SESSION['user_id'] . ")";
if ($db->query($sql)) {
$success = "Project created successfully.";
} else {
$error = "Failed to create project: " . $db->getLastError();
}
break;
case 'update_project':
$id = (int)$_POST['id'];
$projectId = sanitizeInput($_POST['project_id']);
$clientName = sanitizeInput($_POST['client_name']);
$projectTitle = sanitizeInput($_POST['project_title']);
$projectDescription = sanitizeInput($_POST['project_description']);
// Validate required fields
if (empty($projectId) || empty($clientName) || empty($projectTitle)) {
$error = "Please fill in all required fields.";
break;
}
// Check if project ID exists for other projects
$checkId = $db->query("SELECT id FROM projects WHERE project_id = '" . $db->escape($projectId) . "' AND id != $id");
if ($checkId && $checkId->num_rows > 0) {
$error = "Project ID already exists. Please use a different ID.";
break;
}
$sql = "UPDATE projects SET
project_id = '" . $db->escape($projectId) . "',
client_name = '" . $db->escape($clientName) . "',
title = '" . $db->escape($projectTitle) . "',
description = '" . $db->escape($projectDescription) . "'
WHERE id = $id";
if ($db->query($sql)) {
$success = "Project updated successfully.";
} else {
$error = "Failed to update project: " . $db->getLastError();
}
break;
case 'delete_project':
$id = (int)$_POST['id'];
// Delete the project
if ($db->query("DELETE FROM projects WHERE id = $id")) {
$success = "Project deleted successfully.";
} else {
$error = "Failed to delete project: " . $db->getLastError();
}
break;
}
}
// Get all projects with connected surveys
$query = "SELECT p.*,
u.full_name as created_by_name,
DATE_FORMAT(p.created_at, '%b %d, %Y %H:%i') as formatted_date,
(SELECT COUNT(*) FROM project_surveys WHERE project_id = p.id) as connected_surveys
FROM projects p
JOIN users u ON p.created_by = u.id
ORDER BY p.created_at DESC";
$projects = $db->query($query);
?>
Projects |
Project ID
Client
Title
Description
Connected Surveys
Created By
Created Date
Actions
num_rows > 0): ?>
fetch_assoc()): ?>
0) {
$survey_query = $db->query("
SELECT s.title
FROM project_surveys ps
JOIN surveys s ON ps.survey_id = s.id
WHERE ps.project_id = " . $project['id'] . "
LIMIT 1
");
if ($survey_query && $survey_query->num_rows > 0) {
$connected_survey = $survey_query->fetch_assoc()['title'];
}
}
if (!empty($connected_survey)): ?>
None
No projects found. Click "Create Project" to add a new project.
Connected Surveys
Available Surveys
-------------------- END OF FILE --------------------
### FILE 66: syndia.kreahealthcare.com/queue_processor.php
- Type: PHP
- Size: 1.73 KB
- Path: syndia.kreahealthcare.com
- Name: queue_processor.php
------------------------------------------------------------
acquireLock()) {
sleep(5);
continue;
}
$item = $queue->getNextItem('integrity_check');
if ($item) {
try {
$success = $handler->checkRecordIntegrity(
$item['data'],
$handler->getAttributeMetadata()
);
$queue->updateItemStatus(
$item['id'],
$success ? 'completed' : 'failed',
$success ? null : 'Record check failed'
);
// Respect rate limits
sleep(20);
} catch (Exception $e) {
$queue->updateItemStatus(
$item['id'],
'failed',
$e->getMessage()
);
if (stripos($e->getMessage(), 'rate limit') !== false) {
sleep(65); // Wait slightly over a minute
}
}
} else {
sleep(5);
}
$queue->releaseLock();
} catch (Exception $e) {
error_log("Queue processor error: " . $e->getMessage());
$queue->releaseLock();
sleep(5);
}
}
?>
-------------------- END OF FILE --------------------
### FILE 67: syndia.kreahealthcare.com/QueueManager.php
- Type: PHP
- Size: 6.2 KB
- Path: syndia.kreahealthcare.com
- Name: QueueManager.php
------------------------------------------------------------
db = Database::getInstance();
$this->lockFile = sys_get_temp_dir() . '/integrity_check.lock';
$this->initTables();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function initTables() {
// Create queue tables if they don't exist
$this->db->query("
CREATE TABLE IF NOT EXISTS process_queue (
id INT AUTO_INCREMENT PRIMARY KEY,
task_type VARCHAR(50) NOT NULL,
data JSON,
status ENUM('pending', 'processing', 'completed', 'failed') DEFAULT 'pending',
attempts INT DEFAULT 0,
error_message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX (status, task_type)
)
");
$this->db->query("
CREATE TABLE IF NOT EXISTS queue_status (
id INT AUTO_INCREMENT PRIMARY KEY,
task_type VARCHAR(50) NOT NULL,
total_items INT DEFAULT 0,
processed_items INT DEFAULT 0,
failed_items INT DEFAULT 0,
is_running BOOLEAN DEFAULT FALSE,
last_run TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY (task_type)
)
");
}
public function startTask($taskType, $items) {
try {
$this->db->query("START TRANSACTION");
// Clear existing queue for this task type
$this->db->query("DELETE FROM process_queue WHERE task_type = '{$taskType}'");
// Insert new items
$stmt = $this->db->prepare("
INSERT INTO process_queue (task_type, data)
VALUES (?, ?)
");
foreach ($items as $item) {
$stmt->bind_param('ss', $taskType, json_encode($item));
$stmt->execute();
}
// Update queue status
$this->db->query("
INSERT INTO queue_status (task_type, total_items, is_running)
VALUES ('{$taskType}', " . count($items) . ", TRUE)
ON DUPLICATE KEY UPDATE
total_items = VALUES(total_items),
processed_items = 0,
failed_items = 0,
is_running = TRUE,
last_run = NOW()
");
$this->db->query("COMMIT");
return true;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
throw $e;
}
}
public function getNextItem($taskType) {
try {
$this->db->query("START TRANSACTION");
$sql = "
SELECT id, data
FROM process_queue
WHERE task_type = ?
AND status = 'pending'
AND attempts < 3
ORDER BY id ASC
LIMIT 1
FOR UPDATE
";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('s', $taskType);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
// Mark as processing
$this->db->query("
UPDATE process_queue
SET status = 'processing',
attempts = attempts + 1
WHERE id = {$row['id']}
");
$this->db->query("COMMIT");
return [
'id' => $row['id'],
'data' => json_decode($row['data'], true)
];
}
$this->db->query("COMMIT");
return null;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
throw $e;
}
}
public function updateItemStatus($id, $status, $errorMessage = null) {
$stmt = $this->db->prepare("
UPDATE process_queue
SET status = ?,
error_message = ?
WHERE id = ?
");
$stmt->bind_param('ssi', $status, $errorMessage, $id);
$stmt->execute();
// Update queue status
$this->updateQueueStatus();
}
public function updateQueueStatus() {
$this->db->query("
UPDATE queue_status qs
SET processed_items = (
SELECT COUNT(*) FROM process_queue
WHERE task_type = qs.task_type
AND status = 'completed'
),
failed_items = (
SELECT COUNT(*) FROM process_queue
WHERE task_type = qs.task_type
AND status = 'failed'
),
is_running = EXISTS (
SELECT 1 FROM process_queue
WHERE task_type = qs.task_type
AND status IN ('pending', 'processing')
)
");
}
public function getQueueStatus($taskType) {
$result = $this->db->query("
SELECT * FROM queue_status
WHERE task_type = '{$taskType}'
LIMIT 1
");
return $result ? $result->fetch_assoc() : null;
}
public function isLocked() {
if (file_exists($this->lockFile)) {
$lockTime = filemtime($this->lockFile);
if (time() - $lockTime > 300) { // 5 minute timeout
unlink($this->lockFile);
return false;
}
return true;
}
return false;
}
public function acquireLock() {
if ($this->isLocked()) {
return false;
}
return touch($this->lockFile);
}
public function releaseLock() {
if (file_exists($this->lockFile)) {
unlink($this->lockFile);
}
}
}
?>
-------------------- END OF FILE --------------------
### FILE 68: syndia.kreahealthcare.com/quick_start_optimaize.php
- Type: PHP
- Size: 18.55 KB
- Path: syndia.kreahealthcare.com
- Name: quick_start_optimaize.php
------------------------------------------------------------
🚀 Quick Start OptimAIze";
echo "";
try {
$auth = new Auth();
if (!$auth->isLoggedIn()) {
die("❌ Please log in first
");
}
$db = Database::getInstance();
// Get action parameter
$action = $_GET['action'] ?? '';
if ($action) {
handleAction($action, $db);
} else {
showMainInterface($db);
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
}
function showMainInterface($db) {
echo "";
echo "
🎯 OptimAIze Quick Setup ";
echo "
This will set up and test your enhanced OptimAIze system in one click.
";
// Show current status
$status = getCurrentStatus($db);
echo "
Current Status: ";
echo "
✅ Database: Connected
";
echo "
" .
($status['gpt_helper'] ? '✅' : '❌') . " GptHelper: " .
($status['gpt_helper'] ? 'Available' : 'Not Found') . "
";
echo "
📊 Combinations: " . number_format($status['total_combinations']) . " total, " .
number_format($status['processed_combinations']) . " processed
";
echo "
" .
($status['openai_key'] ? '✅' : '❌') . " OpenAI API: " .
($status['openai_key'] ? 'Configured' : 'Not Configured') . "
";
if ($status['is_running']) {
echo "
⚠️ Analysis is currently running
";
$progress = $status['total_combinations'] > 0 ?
($status['processed_combinations'] / $status['total_combinations']) * 100 : 0;
echo "
";
echo "
Progress: " . number_format($progress, 1) . "%
";
} else {
echo "
⏹ Analysis is stopped
";
}
echo "
";
// Action buttons
echo "";
// Quick stats
if ($status['processed_combinations'] > 0) {
echo "";
echo "
📊 Quick Results: ";
echo "
Possible Combinations: " . number_format($status['possible_combinations']) . "
";
echo "
Impossible Combinations: " . number_format($status['impossible_combinations']) . "
";
if ($status['impossible_combinations'] > 0) {
$impossibleRate = ($status['impossible_combinations'] / $status['processed_combinations']) * 100;
echo "
Impossible Rate: " . number_format($impossibleRate, 1) . "%
";
}
echo "
";
}
echo "";
}
function handleAction($action, $db) {
switch ($action) {
case 'setup_database':
setupDatabase($db);
break;
case 'generate_combinations':
generateCombinations($db);
break;
case 'test_gpt':
testGptConnection($db);
break;
case 'start_analysis':
startAnalysis($db);
break;
case 'stop_analysis':
stopAnalysis($db);
break;
case 'view_results':
viewResults($db);
break;
default:
echo "❌ Unknown action: $action
";
}
echo "← Back to Main ";
}
function getCurrentStatus($db) {
$status = [];
// Check GptHelper
try {
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
$status['gpt_helper'] = class_exists('GptHelper');
} catch (Exception $e) {
$status['gpt_helper'] = false;
}
// Check OpenAI API key
$status['openai_key'] = defined('OPENAI_API_KEY') && !empty(OPENAI_API_KEY);
// Check database columns
$columnCheck = $db->query("SHOW COLUMNS FROM optimization_analysis_state LIKE 'should_pause'");
$status['has_database_columns'] = $columnCheck && $columnCheck->num_rows > 0;
// Get combination counts
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$status['total_combinations'] = $totalQuery ? $totalQuery->fetch_assoc()['count'] : 0;
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$status['processed_combinations'] = $processedQuery ? $processedQuery->fetch_assoc()['count'] : 0;
$possibleQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 0");
$status['possible_combinations'] = $possibleQuery ? $possibleQuery->fetch_assoc()['count'] : 0;
$impossibleQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1");
$status['impossible_combinations'] = $impossibleQuery ? $impossibleQuery->fetch_assoc()['count'] : 0;
// Check if analysis is running
$stateQuery = $db->query("SELECT is_running FROM optimization_analysis_state WHERE is_running = 1 LIMIT 1");
$status['is_running'] = $stateQuery && $stateQuery->num_rows > 0;
return $status;
}
function setupDatabase($db) {
echo "🛠 Setting Up Database ";
try {
// Add should_pause column if missing
$columnCheck = $db->query("SHOW COLUMNS FROM optimization_analysis_state LIKE 'should_pause'");
if (!$columnCheck || $columnCheck->num_rows == 0) {
$result = $db->query("ALTER TABLE optimization_analysis_state ADD COLUMN should_pause TINYINT(1) DEFAULT 0 AFTER is_running");
if ($result) {
echo "✅ Added 'should_pause' column
";
} else {
echo "❌ Failed to add 'should_pause' column
";
}
} else {
echo "✅ Database columns already exist
";
}
// Reset any stuck states
$db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0 WHERE is_running = 1");
echo "✅ Reset any stuck analysis states
";
} catch (Exception $e) {
echo "❌ Database setup failed: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function generateCombinations($db) {
echo "🔄 Generating Combinations ";
try {
// Get attributes
$attributesQuery = $db->query("SELECT id, name, choices FROM attributes ORDER BY id");
$attributes = [];
while ($attr = $attributesQuery->fetch_assoc()) {
$choices = json_decode($attr['choices'], true);
if ($choices && is_array($choices)) {
$attributes[] = [
'id' => $attr['id'],
'name' => $attr['name'],
'choices' => $choices
];
}
}
if (count($attributes) < 2) {
throw new Exception("Need at least 2 attributes to generate combinations");
}
echo "Found " . count($attributes) . " attributes
";
$generatedCount = 0;
$stmt = $db->prepare("INSERT IGNORE INTO panel_directives
(attribute1_id, attribute2_id, choice1, choice2, attribute1_name, attribute2_name, status)
VALUES (?, ?, ?, ?, ?, ?, 'pending')");
// Generate combinations
for ($i = 0; $i < count($attributes); $i++) {
for ($j = $i + 1; $j < count($attributes); $j++) {
$attr1 = $attributes[$i];
$attr2 = $attributes[$j];
foreach ($attr1['choices'] as $choice1) {
foreach ($attr2['choices'] as $choice2) {
$stmt->bind_param('iissss',
$attr1['id'], $attr2['id'],
$choice1, $choice2,
$attr1['name'], $attr2['name']
);
if ($stmt->execute()) {
$generatedCount++;
}
}
}
}
}
echo "✅ Generated " . number_format($generatedCount) . " combinations
";
} catch (Exception $e) {
echo "❌ Generation failed: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function testGptConnection($db) {
echo "🤖 Testing GPT Connection ";
try {
if (!class_exists('GptHelper')) {
require_once 'includes/GptHelper.php';
}
if (!class_exists('GptHelper')) {
throw new Exception("GptHelper class not found");
}
echo "✅ GptHelper class loaded
";
if (!defined('OPENAI_API_KEY') || empty(OPENAI_API_KEY)) {
throw new Exception("OpenAI API key not configured");
}
echo "✅ OpenAI API key configured
";
// Test basic request
$messages = [
[
'role' => 'user',
'content' => 'Respond with exactly: "TEST SUCCESSFUL"'
]
];
echo "🔄 Sending test request...
";
$response = GptHelper::makeRequest($messages, 'gpt-4', 0.1);
if ($response['success']) {
echo "✅ GPT API test successful!
";
echo "Response: " . htmlspecialchars($response['response']) . "
";
} else {
throw new Exception("GPT API test failed: " . $response['error']);
}
} catch (Exception $e) {
echo "❌ GPT test failed: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function startAnalysis($db) {
echo "🚀 Starting Analysis ";
try {
// Check if already running
$stateQuery = $db->query("SELECT is_running FROM optimization_analysis_state WHERE is_running = 1 LIMIT 1");
if ($stateQuery && $stateQuery->num_rows > 0) {
echo "⚠️ Analysis is already running
";
return;
}
// Get total combinations
$totalQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalQuery->fetch_assoc()['count'];
if ($totalCombinations == 0) {
echo "❌ No combinations found. Generate combinations first.
";
return;
}
// Get processed count
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$processedCount = $processedQuery->fetch_assoc()['count'];
// Update or create analysis state
$existingState = $db->query("SELECT id FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
if ($existingState && $existingState->num_rows > 0) {
$stateId = $existingState->fetch_assoc()['id'];
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 1,
started_at = NOW(),
total_combinations = ?,
processed_combinations = ?,
should_pause = 0,
completed_at = NULL
WHERE id = ?");
$stmt->bind_param('iii', $totalCombinations, $processedCount, $stateId);
} else {
$stmt = $db->prepare("INSERT INTO optimization_analysis_state
(total_combinations, processed_combinations, is_running, started_at, should_pause)
VALUES (?, ?, 1, NOW(), 0)");
$stmt->bind_param('ii', $totalCombinations, $processedCount);
}
if (!$stmt->execute()) {
throw new Exception("Failed to update analysis state");
}
echo "✅ Analysis state updated
";
echo "📊 Total combinations: " . number_format($totalCombinations) . "
";
echo "📊 Already processed: " . number_format($processedCount) . "
";
echo "📊 Remaining: " . number_format($totalCombinations - $processedCount) . "
";
// Start background process
$processFile = file_exists('enhanced_process_optimization.php') ?
'enhanced_process_optimization.php' :
'process_optimization_analysis.php';
$command = "php " . __DIR__ . "/$processFile > /dev/null 2>&1 &";
exec($command);
echo "✅ Background process started using: $processFile
";
echo "💡 You can now monitor progress on the OptimAIze page
";
} catch (Exception $e) {
echo "❌ Failed to start analysis: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function stopAnalysis($db) {
echo "⏹ Stopping Analysis ";
try {
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 0,
should_pause = 0,
completed_at = NOW()
WHERE is_running = 1");
if ($stmt->execute()) {
echo "✅ Analysis stopped successfully
";
} else {
echo "❌ Failed to stop analysis
";
}
} catch (Exception $e) {
echo "❌ Error stopping analysis: " . htmlspecialchars($e->getMessage()) . "
";
}
}
function viewResults($db) {
echo "📊 Analysis Results ";
try {
// Get recent possible combinations
$possibleQuery = $db->query("
SELECT attribute1_name, choice1, attribute2_name, choice2, updated_at
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 0
ORDER BY updated_at DESC
LIMIT 5
");
echo "Recent Possible Combinations (Last 5): ";
if ($possibleQuery && $possibleQuery->num_rows > 0) {
echo "";
while ($row = $possibleQuery->fetch_assoc()) {
echo "{$row['attribute1_name']}={$row['choice1']} + {$row['attribute2_name']}={$row['choice2']} (" . date('H:i:s', strtotime($row['updated_at'])) . ") ";
}
echo " ";
} else {
echo "No possible combinations analyzed yet
";
}
// Get impossible combinations
$impossibleQuery = $db->query("
SELECT attribute1_name, choice1, attribute2_name, choice2, llm_reasoning, updated_at
FROM panel_directives
WHERE llm_checked = 1 AND is_impossible = 1
ORDER BY updated_at DESC
LIMIT 10
");
echo "Impossible Combinations (Last 10): ";
if ($impossibleQuery && $impossibleQuery->num_rows > 0) {
echo "";
while ($row = $impossibleQuery->fetch_assoc()) {
echo "{$row['attribute1_name']}={$row['choice1']} + {$row['attribute2_name']}={$row['choice2']} ";
echo "" . htmlspecialchars(substr($row['llm_reasoning'], 0, 100)) . "... (" . date('H:i:s', strtotime($row['updated_at'])) . ") ";
}
echo " ";
} else {
echo "No impossible combinations found yet
";
}
} catch (Exception $e) {
echo "❌ Error viewing results: " . htmlspecialchars($e->getMessage()) . "
";
}
}
?>
-------------------- END OF FILE --------------------
### FILE 69: syndia.kreahealthcare.com/save_survey_question.php
- Type: PHP
- Size: 3.56 KB
- Path: syndia.kreahealthcare.com
- Name: save_survey_question.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Get and validate input
$surveyId = isset($_POST['survey_id']) ? (int)$_POST['survey_id'] : null;
$questionId = isset($_POST['question_id']) ? (int)$_POST['question_id'] : null;
$questionType = isset($_POST['questionType']) ? $_POST['questionType'] : null;
$questionText = isset($_POST['questionText']) ? trim($_POST['questionText']) : null;
$helpText = isset($_POST['helpText']) ? trim($_POST['helpText']) : '';
$isRequired = isset($_POST['isRequired']) ? 1 : 0;
if (!$surveyId || !$questionType || !$questionText) {
throw new Exception('Missing required fields');
}
// Verify user has access to this survey
$db = Database::getInstance();
$stmt = $db->prepare("SELECT id FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
throw new Exception('Access denied');
}
// Process options for choice questions
$options = null;
if (in_array($questionType, ['single_choice', 'multiple_choice', 'dropdown'])) {
$options = $_POST['options'] ?? null;
}
// Process configuration
$config = $_POST['config'] ?? null;
// Get max order for new questions
$questionOrder = 0;
if (!$questionId) {
$sql = "SELECT MAX(question_order) as max_order FROM survey_questions WHERE survey_id = ?";
$stmt = $db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$result = $stmt->get_result()->fetch_assoc();
$questionOrder = ($result['max_order'] ?? 0) + 1;
}
if ($questionId) {
// Update existing question
$sql = "UPDATE survey_questions
SET question_text = ?,
question_type = ?,
help_text = ?,
options = ?,
config = ?,
is_required = ?
WHERE id = ? AND survey_id = ?";
$stmt = $db->prepare($sql);
$stmt->bind_param('sssssiis',
$questionText,
$questionType,
$helpText,
$options,
$config,
$isRequired,
$questionId,
$surveyId
);
} else {
// Create new question
$sql = "INSERT INTO survey_questions
(survey_id, question_text, question_type, help_text, options, config, is_required, question_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $db->prepare($sql);
$stmt->bind_param('isssssii',
$surveyId,
$questionText,
$questionType,
$helpText,
$options,
$config,
$isRequired,
$questionOrder
);
}
if (!$stmt->execute()) {
throw new Exception("Failed to save question: " . $db->getLastError());
}
$newId = $questionId ?: $db->getLastInsertId();
echo json_encode([
'success' => true,
'question_id' => $newId,
'message' => 'Question saved successfully'
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 70: syndia.kreahealthcare.com/save_survey.php
- Type: PHP
- Size: 1.81 KB
- Path: syndia.kreahealthcare.com
- Name: save_survey.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$surveyManager = SurveyManager::getInstance();
// Get and validate input
$data = [
'title' => trim($_POST['title'] ?? ''),
'description' => trim($_POST['description'] ?? ''),
'status' => $_POST['status'] ?? 'draft',
'allow_multiple' => !empty($_POST['allow_multiple']),
'allow_edit' => !empty($_POST['allow_edit']),
'created_by' => $_SESSION['user_id']
];
// Validate required fields
if (empty($data['title'])) {
throw new Exception('Survey title is required');
}
// Check if survey_id exists and is not empty
$surveyId = isset($_POST['survey_id']) && !empty($_POST['survey_id']) ?
(int)$_POST['survey_id'] : null;
// Create or update survey
if ($surveyId) {
$result = $surveyManager->updateSurvey($surveyId, $data);
} else {
$result = $surveyManager->createSurvey($data);
// Get the new survey ID if available
$surveyId = isset($result['survey_id']) ? $result['survey_id'] : null;
}
if (!$result['success']) {
throw new Exception($result['error'] ?? 'Operation failed');
}
echo json_encode([
'success' => true,
'survey_id' => $surveyId,
'message' => 'Survey saved successfully'
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 71: syndia.kreahealthcare.com/simple_foreground_processor.php
- Type: PHP
- Size: 8.73 KB
- Path: syndia.kreahealthcare.com
- Name: simple_foreground_processor.php
------------------------------------------------------------
query("SELECT id, attribute1_name, choice1, attribute2_name, choice2 FROM panel_directives WHERE llm_checked = 0 LIMIT 5");
if (!$query || $query->num_rows === 0) {
echo json_encode([
'success' => true,
'has_more' => false,
'processed' => 0,
'progress' => ['total' => 0, 'processed' => 0, 'remaining' => 0, 'percentage' => 100],
'message' => 'All combinations processed'
]);
exit;
}
$processed = 0;
$results = [];
// Process all combinations in this batch
while ($combo = $query->fetch_assoc()) {
// Process the combination
$result = GptHelper::analyzeCombination(
$combo['attribute1_name'],
$combo['choice1'],
$combo['attribute2_name'],
$combo['choice2']
);
if ($result['success']) {
$isImpossible = $result['is_impossible'] ? 1 : 0;
$reasoning = $result['reasoning'];
// Update database
$updateStmt = $db->prepare("UPDATE panel_directives SET llm_checked = 1, is_impossible = ?, llm_reasoning = ? WHERE id = ?");
$updateStmt->bind_param('isi', $isImpossible, $reasoning, $combo['id']);
$updateStmt->execute();
$processed++;
$results[] = [
'combination' => "{$combo['attribute1_name']}={$combo['choice1']} + {$combo['attribute2_name']}={$combo['choice2']}",
'result' => $isImpossible ? 'IMPOSSIBLE' : 'POSSIBLE'
];
} else {
// If one fails, return error
echo json_encode([
'success' => false,
'has_more' => true,
'error' => $result['error'],
'progress' => ['total' => 0, 'processed' => 0, 'remaining' => 0, 'percentage' => 0]
]);
exit;
}
}
// Get updated counts
$totalQuery = $db->query("SELECT COUNT(*) as total FROM panel_directives");
$total = $totalQuery->fetch_assoc()['total'];
$processedQuery = $db->query("SELECT COUNT(*) as processed FROM panel_directives WHERE llm_checked = 1");
$totalProcessed = $processedQuery->fetch_assoc()['processed'];
$hasMore = $totalProcessed < $total;
$percentage = $total > 0 ? ($totalProcessed / $total) * 100 : 100;
echo json_encode([
'success' => true,
'has_more' => $hasMore,
'processed' => $processed,
'progress' => [
'total' => (int)$total,
'processed' => (int)$totalProcessed,
'remaining' => (int)($total - $totalProcessed),
'percentage' => round($percentage, 1)
],
'results' => $results,
'batch_size' => $processed
]);
} catch (Exception $e) {
echo json_encode([
'success' => false,
'has_more' => false,
'error' => $e->getMessage(),
'progress' => ['total' => 0, 'processed' => 0, 'remaining' => 0, 'percentage' => 0]
]);
}
exit;
}
// BROWSER MODE - HTML output
?>
OptimAIze Processor
OptimAIze Processor
✅ All files loaded successfully";
$db = Database::getInstance();
echo "✅ Database connected
";
// Check pending combinations
$pendingQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 0");
$pending = $pendingQuery->fetch_assoc()['count'];
$processedQuery = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$processed = $processedQuery->fetch_assoc()['count'];
echo "📊 Pending: " . number_format($pending) . " | Processed: " . number_format($processed) . "
";
if ($pending == 0) {
echo "🎉 All combinations have been processed!
";
echo "View OptimAIze Dashboard | Back to Main Site
";
} else {
if (isset($_GET['process'])) {
echo "
🔄 Processing Combinations... ";
$batchSize = 5;
$query = $db->query("SELECT id, attribute1_name, choice1, attribute2_name, choice2 FROM panel_directives WHERE llm_checked = 0 LIMIT $batchSize");
$count = 0;
while ($combo = $query->fetch_assoc()) {
$count++;
echo "[$count] Processing: {$combo['attribute1_name']}={$combo['choice1']} + {$combo['attribute2_name']}={$combo['choice2']}
";
flush();
$result = GptHelper::analyzeCombination(
$combo['attribute1_name'],
$combo['choice1'],
$combo['attribute2_name'],
$combo['choice2']
);
if ($result['success']) {
$isImpossible = $result['is_impossible'] ? 1 : 0;
$reasoning = $result['reasoning'];
$updateStmt = $db->prepare("UPDATE panel_directives SET llm_checked = 1, is_impossible = ?, llm_reasoning = ? WHERE id = ?");
$updateStmt->bind_param('isi', $isImpossible, $reasoning, $combo['id']);
$updateStmt->execute();
echo "✅ " . ($isImpossible ? 'IMPOSSIBLE' : 'POSSIBLE') . " - " . substr($reasoning, 0, 60) . "...
";
} else {
echo "❌ Error: " . htmlspecialchars($result['error']) . "
";
break;
}
flush();
// Removed sleep(1) for faster processing
}
echo "✅ Batch of $count combinations completed!
";
echo "🔄 Process Another Batch
";
} else {
echo "🚀 Ready to Process ";
echo "▶️ Start Processing (Batch of 5)
";
echo "Note: This will process 5 combinations at a time. Click multiple times to process all.
";
}
}
} catch (Exception $e) {
echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "
";
echo "Check your configuration and try again.
";
}
?>
📊 View OptimAIze Dashboard | 🏠 Back to Main Site
-------------------- END OF FILE --------------------
### FILE 72: syndia.kreahealthcare.com/start_optimization_analysis.php
- Type: PHP
- Size: 7.21 KB
- Path: syndia.kreahealthcare.com
- Name: start_optimization_analysis.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
$db = Database::getInstance();
// Get input data
$input = json_decode(file_get_contents('php://input'), true);
$action = $input['action'] ?? '';
switch ($action) {
case 'start':
$result = startAnalysis($db, $input);
break;
case 'pause':
$result = pauseAnalysis($db);
break;
case 'stop':
$result = stopAnalysis($db);
break;
case 'reset':
$result = resetAnalysis($db);
break;
default:
throw new Exception('Invalid action');
}
echo json_encode($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
function startAnalysis($db, $input) {
try {
// Check if analysis is already running
$stateQuery = $db->query("SELECT * FROM optimization_analysis_state ORDER BY id DESC LIMIT 1");
$state = $stateQuery ? $stateQuery->fetch_assoc() : null;
if ($state && $state['is_running']) {
return [
'success' => false,
'message' => 'Analysis is already running'
];
}
// Get total combinations
$totalResult = $db->query("SELECT COUNT(*) as count FROM panel_directives");
$totalCombinations = $totalResult ? $totalResult->fetch_assoc()['count'] : 0;
if ($totalCombinations == 0) {
return [
'success' => false,
'message' => 'No combinations found. Generate combinations first in the Base section.'
];
}
// **PRESERVE EXISTING PROGRESS** - Count what's already been processed
$processedResult = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1");
$currentProcessed = $processedResult ? $processedResult->fetch_assoc()['count'] : 0;
// Use the progress sent from frontend if available, otherwise use database count
$preserveProgress = $input['preserve_progress'] ?? true;
$frontendProgress = $input['current_progress'] ?? 0;
// Use the higher of the two to ensure we never go backwards
$actualProgress = max($currentProcessed, $frontendProgress);
// Update or create analysis state WITHOUT resetting progress
if ($state) {
// Update existing state, preserving progress
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 1,
should_pause = 0,
started_at = NOW(),
completed_at = NULL,
total_combinations = ?,
processed_combinations = GREATEST(processed_combinations, ?, ?)
WHERE id = ?");
$stmt->bind_param('iiii', $totalCombinations, $actualProgress, $currentProcessed, $state['id']);
} else {
// Create new state with current progress
$stmt = $db->prepare("INSERT INTO optimization_analysis_state
(total_combinations, processed_combinations, is_running, started_at, should_pause)
VALUES (?, ?, 1, NOW(), 0)");
$stmt->bind_param('ii', $totalCombinations, $actualProgress);
}
if (!$stmt->execute()) {
throw new Exception("Failed to update analysis state: " . $db->getLastError());
}
// Start background process
$processFile = file_exists('enhanced_process_optimization.php') ?
'enhanced_process_optimization.php' :
'process_optimization_analysis.php';
if (function_exists('exec')) {
$command = "php " . __DIR__ . "/$processFile > /dev/null 2>&1 &";
exec($command, $output, $returnCode);
if ($returnCode !== 0) {
error_log("Warning: Background process may not have started properly. Return code: $returnCode");
}
} else {
error_log("Warning: exec() function not available. Background processing may not work.");
}
$remaining = $totalCombinations - $actualProgress;
return [
'success' => true,
'message' => 'Analysis started successfully',
'total_combinations' => $totalCombinations,
'current_progress' => $actualProgress,
'remaining' => $remaining,
'resumed_from' => $actualProgress > 0,
'process_file' => $processFile
];
} catch (Exception $e) {
error_log("Error starting analysis: " . $e->getMessage());
return [
'success' => false,
'message' => 'Failed to start analysis: ' . $e->getMessage()
];
}
}
function pauseAnalysis($db) {
try {
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
should_pause = 1
WHERE is_running = 1");
if ($stmt->execute()) {
return [
'success' => true,
'message' => 'Analysis paused successfully'
];
} else {
throw new Exception("Failed to pause analysis");
}
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Failed to pause analysis: ' . $e->getMessage()
];
}
}
function stopAnalysis($db) {
try {
$stmt = $db->prepare("UPDATE optimization_analysis_state SET
is_running = 0,
should_pause = 0,
completed_at = NOW()
WHERE is_running = 1");
if ($stmt->execute()) {
return [
'success' => true,
'message' => 'Analysis stopped successfully'
];
} else {
throw new Exception("Failed to stop analysis");
}
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Failed to stop analysis: ' . $e->getMessage()
];
}
}
function resetAnalysis($db) {
try {
// First stop any running analysis
$db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0");
// Reset all progress (only if user explicitly wants to reset)
$db->query("UPDATE panel_directives SET llm_checked = 0, is_impossible = 0, llm_reasoning = NULL, status = 'pending'");
// Reset analysis state
$db->query("UPDATE optimization_analysis_state SET
processed_combinations = 0,
completed_at = NULL,
started_at = NULL");
return [
'success' => true,
'message' => 'Analysis reset successfully. All progress cleared.'
];
} catch (Exception $e) {
return [
'success' => false,
'message' => 'Failed to reset analysis: ' . $e->getMessage()
];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 73: syndia.kreahealthcare.com/status_check.php
- Type: PHP
- Size: 7.72 KB
- Path: syndia.kreahealthcare.com
- Name: status_check.php
------------------------------------------------------------
🔍 Quick System Status Check";
echo "";
try {
// Test 1: Check configuration
echo "1. Configuration Check ";
if (defined('COST_EFFECTIVE_MODE') && COST_EFFECTIVE_MODE) {
echo "✅ Cost-effective mode is active
";
echo "📊 Using model: " . GPT_MODEL . "
";
echo "📊 Max tokens: " . GPT_MAX_TOKENS . "
";
echo "📊 Requests per minute: " . GPT_REQUESTS_PER_MINUTE . "
";
if (defined('MAX_DAILY_COST')) {
echo "💰 Daily cost limit: $" . MAX_DAILY_COST . "
";
}
} else {
echo "⚠️ Cost-effective mode not detected - make sure you uploaded the updated config.php
";
}
// Test 2: Database connection
echo "2. Database Connection ";
$db = Database::getInstance();
echo "✅ Database connected successfully
";
// Test 3: Check OptimAIze status
echo "3. OptimAIze Status ";
$totalResult = $db->query("SELECT COUNT(*) as total FROM panel_directives");
$totalDirectives = $totalResult->fetch_assoc()['total'];
$checkedResult = $db->query("SELECT COUNT(*) as checked FROM panel_directives WHERE llm_checked = 1");
$checkedDirectives = $checkedResult->fetch_assoc()['checked'];
$uncheckedResult = $db->query("SELECT COUNT(*) as unchecked FROM panel_directives WHERE llm_checked = 0");
$uncheckedDirectives = $uncheckedResult->fetch_assoc()['unchecked'];
echo "📊 Total combinations: " . number_format($totalDirectives) . "
";
echo "✅ Already processed: " . number_format($checkedDirectives) . " (" . round(($checkedDirectives/$totalDirectives)*100, 1) . "%)
";
echo "⏳ Remaining: " . number_format($uncheckedDirectives) . " (" . round(($uncheckedDirectives/$totalDirectives)*100, 1) . "%)
";
// Test 4: Cost estimation
echo "4. Cost Estimation with New Settings ";
$avgTokensPerRequest = defined('AVERAGE_TOKENS_PER_REQUEST') ? AVERAGE_TOKENS_PER_REQUEST : 200;
$costPer1kTokens = defined('GPT35_COST_PER_1K_TOKENS') ? GPT35_COST_PER_1K_TOKENS : 0.002;
$estimatedCostRemaining = ($uncheckedDirectives * $avgTokensPerRequest * $costPer1kTokens) / 1000;
echo "💰 Model: " . GPT_MODEL . "
";
echo "💰 Cost per 1K tokens: $" . number_format($costPer1kTokens, 4) . "
";
echo "💰 Estimated cost to complete: $" . number_format($estimatedCostRemaining, 2) . "
";
// Compare with GPT-4 cost
$gpt4Cost = ($uncheckedDirectives * $avgTokensPerRequest * 0.03) / 1000;
$savings = $gpt4Cost - $estimatedCostRemaining;
echo "🎉 Cost savings vs GPT-4: $" . number_format($savings, 2) . " (" . round((1 - $estimatedCostRemaining/$gpt4Cost)*100, 1) . "% cheaper!)
";
// Test 5: Cache status
echo "5. Cache System ";
$cacheStats = GptHelper::getCacheStats();
echo "📊 Cache statistics:
";
echo "" . json_encode($cacheStats, JSON_PRETTY_PRINT) . " ";
if ($cacheStats['total_cached'] > 0) {
echo "✅ Cache is working - {$cacheStats['total_cached']} combinations cached
";
echo "💰 Estimated savings from cache: $" . number_format($cacheStats['cost_saved_by_cache'], 2) . "
";
} else {
echo "ℹ️ No cached combinations yet - cache will build as processing runs
";
}
// Test 6: API Test
echo "6. OpenAI API Test ";
echo "🔍 Testing API connection with new settings...
";
try {
$result = GptHelper::analyzeCombination('Age', '5 years', 'Education', 'PhD');
echo "✅ API test successful!
";
echo "📊 Result: " . ($result['is_impossible'] ? 'IMPOSSIBLE' : 'POSSIBLE') . "
";
echo "💡 Reasoning: " . htmlspecialchars($result['reasoning']) . "
";
if (isset($result['daily_cost'])) {
echo "💰 Daily cost so far: $" . number_format($result['daily_cost'], 4) . "
";
}
if (isset($result['model_used'])) {
echo "🤖 Model used: " . $result['model_used'] . "
";
}
if (isset($result['cached']) && $result['cached']) {
echo "⚡ Result was cached - no API cost!
";
}
} catch (Exception $e) {
echo "❌ API test failed: " . htmlspecialchars($e->getMessage()) . "
";
if (strpos($e->getMessage(), 'quota') !== false || strpos($e->getMessage(), 'billing') !== false) {
echo "🚨 This is still a billing/quota issue. You need to add credits to your OpenAI account.
";
echo "";
}
}
// Test 7: Rate limit status
echo "7. Rate Limit Status ";
$rateLimitStatus = GptHelper::getRateLimitStatus(true);
echo "📊 Rate limit status:
";
echo "" . json_encode($rateLimitStatus, JSON_PRETTY_PRINT) . " ";
} catch (Exception $e) {
echo "❌ System check failed: " . htmlspecialchars($e->getMessage()) . "
";
}
echo "📋 What to Do Next ";
echo "";
echo "
If API test was successful: ";
echo "
";
echo "Start small test: Process 10-20 combinations first ";
echo "Monitor costs: Check the daily cost tracking ";
echo "Scale up gradually: Increase batch sizes if all goes well ";
echo "Use your OptimAIze page: The enhanced system should work much better now ";
echo " ";
echo "
";
echo "";
echo "
If API test failed: ";
echo "
";
echo "Fix OpenAI billing: Add credits to your account ";
echo "Check account status: Make sure it's active ";
echo "Wait 10-15 minutes: After adding credits, then test again ";
echo "Contact me: If issues persist, let me know the exact error ";
echo " ";
echo "
";
echo "";
echo "
✅ System Improvements Applied: ";
echo "
";
echo "🤖 Using GPT-3.5-turbo (90% cheaper than GPT-4) ";
echo "💰 Daily cost limits to prevent overspending ";
echo "🗄️ Intelligent caching to reduce API calls ";
echo "⚡ Better rate limiting and error recovery ";
echo "📊 Real-time cost tracking ";
echo " ";
echo "
";
?>
-------------------- END OF FILE --------------------
### FILE 74: syndia.kreahealthcare.com/survey_form.php
- Type: PHP
- Size: 48.98 KB
- Path: syndia.kreahealthcare.com
- Name: survey_form.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$surveyManager = SurveyManager::getInstance();
// Get survey details if editing
$surveyId = isset($_GET['id']) ? (int)$_GET['id'] : null;
$survey = null;
if ($surveyId) {
$survey = $surveyManager->getSurveyDetails($surveyId, $_SESSION['user_id']);
if (!$survey) {
redirectTo('surveys.php');
}
}
?>
|
-------------------- END OF FILE --------------------
### FILE 75: syndia.kreahealthcare.com/survey_preview.php
- Type: PHP
- Size: 18.15 KB
- Path: syndia.kreahealthcare.com
- Name: survey_preview.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$surveyId = isset($_GET['id']) ? (int)$_GET['id'] : null;
if (!$surveyId) {
redirectTo('surveys.php');
}
// Get survey details
$surveyManager = SurveyManager::getInstance();
$survey = $surveyManager->getSurveyDetails($surveyId, $_SESSION['user_id']);
if (!$survey) {
redirectTo('surveys.php');
}
// Get survey questions
$questions = $surveyManager->getSurveyQuestions($surveyId);
?>
Survey Preview |
";
break;
case 'long_text':
$html = " ";
break;
case 'single_choice':
$html = "";
foreach ($options as $option) {
$html .= "
" . htmlspecialchars($option) . "
";
}
if (!empty($config['allowOther'])) {
$html .= "
Other
";
}
$html .= "
";
break;
case 'multiple_choice':
$html = "";
foreach ($options as $option) {
$html .= "
" . htmlspecialchars($option) . "
";
}
if (!empty($config['allowOther'])) {
$html .= "
Other
";
}
$html .= "
";
break;
case 'dropdown':
$html = "
-- Select an option -- ";
foreach ($options as $option) {
$html .= "" .
htmlspecialchars($option) . " ";
}
$html .= " ";
break;
case 'rating_scale':
$start = $config['start'] ?? 1;
$end = $config['end'] ?? 5;
$startLabel = $config['startLabel'] ?? '';
$endLabel = $config['endLabel'] ?? '';
$html = "";
if ($startLabel) {
$html .= "
" . htmlspecialchars($startLabel) . "
";
}
$html .= "
";
for ($i = $start; $i <= $end; $i++) {
$html .= "
$i
";
}
$html .= "
";
if ($endLabel) {
$html .= "
" . htmlspecialchars($endLabel) . "
";
}
$html .= "
";
break;
case 'linear_scale':
$labels = $config['scale_labels'] ?? ['Strongly Disagree', 'Disagree', 'Neutral', 'Agree', 'Strongly Agree'];
$html = "";
foreach ($labels as $index => $label) {
$html .= "
" . htmlspecialchars($label) . "
";
}
$html .= "
";
break;
case 'matrix_single':
case 'matrix_multiple':
$rows = $config['rows'] ?? [];
$columns = $config['columns'] ?? [];
$type = $question['question_type'] === 'matrix_single' ? 'radio' : 'checkbox';
$html = "";
break;
case 'number':
$min = isset($config['min']) ? "min='{$config['min']}'" : '';
$max = isset($config['max']) ? "max='{$config['max']}'" : '';
$step = isset($config['step']) ? "step='{$config['step']}'" : 'step="any"';
$html = " ";
break;
case 'date':
$html = " ";
break;
case 'email':
$html = " ";
break;
case 'phone':
$html = " ";
break;
case 'section_header':
$html = "";
break;
case 'descriptive_text':
$html = "" .
nl2br(htmlspecialchars($question['question_text'])) . "
";
break;
case 'page_break':
$html = " ";
break;
default:
$html = " ";
}
return $html;
}
?>
-------------------- END OF FILE --------------------
### FILE 76: syndia.kreahealthcare.com/surveys.php
- Type: PHP
- Size: 24.34 KB
- Path: syndia.kreahealthcare.com
- Name: surveys.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
$surveyManager = SurveyManager::getInstance();
// Get surveys count for analytics
$totalSurveys = $db->query("SELECT COUNT(*) as count FROM surveys WHERE created_by = " . $_SESSION['user_id'])->fetch_assoc()['count'] ?? 0;
$activeSurveys = $db->query("SELECT COUNT(*) as count FROM surveys WHERE status = 'active' AND created_by = " . $_SESSION['user_id'])->fetch_assoc()['count'] ?? 0;
$completedSurveys = $db->query("SELECT COUNT(*) as count FROM surveys WHERE status = 'completed' AND created_by = " . $_SESSION['user_id'])->fetch_assoc()['count'] ?? 0;
?>
Surveys |
-------------------- END OF FILE --------------------
### FILE 77: syndia.kreahealthcare.com/update_directive_status.php
- Type: PHP
- Size: 3.43 KB
- Path: syndia.kreahealthcare.com
- Name: update_directive_status.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Check if user is admin (only admins can approve/decline directives)
if (!$auth->isAdmin()) {
throw new Exception('Admin access required');
}
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['id']) || !isset($input['status'])) {
throw new Exception('Missing required parameters: id and status');
}
$id = (int)$input['id'];
$status = $input['status'];
// Validate status
if (!in_array($status, ['pending', 'approved', 'declined'])) {
throw new Exception('Invalid status. Must be: pending, approved, or declined');
}
$db = Database::getInstance();
// First, verify the directive exists and is impossible
$checkStmt = $db->prepare("
SELECT id, is_impossible, status, attribute1_name, choice1, attribute2_name, choice2
FROM panel_directives
WHERE id = ? AND llm_checked = 1 AND is_impossible = 1
");
$checkStmt->bind_param('i', $id);
$checkStmt->execute();
$directive = $checkStmt->get_result()->fetch_assoc();
if (!$directive) {
throw new Exception('Directive not found or not marked as impossible');
}
// Check if status is actually changing
if ($directive['status'] === $status) {
echo json_encode([
'success' => true,
'message' => 'Status is already set to ' . $status,
'directive' => [
'id' => $id,
'status' => $status,
'combination' => $directive['attribute1_name'] . ' = ' . $directive['choice1'] . ' + ' . $directive['attribute2_name'] . ' = ' . $directive['choice2']
]
]);
exit;
}
// Update directive status
$updateStmt = $db->prepare("
UPDATE panel_directives
SET status = ?, updated_at = NOW()
WHERE id = ?
");
$updateStmt->bind_param('si', $status, $id);
if (!$updateStmt->execute()) {
throw new Exception('Failed to update directive status');
}
// Log the status change for audit purposes
$logStmt = $db->prepare("
INSERT INTO directive_status_log (directive_id, old_status, new_status, changed_by, changed_at)
VALUES (?, ?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE
old_status = VALUES(old_status),
new_status = VALUES(new_status),
changed_by = VALUES(changed_by),
changed_at = VALUES(changed_at)
");
if ($logStmt) {
$logStmt->bind_param('issi', $id, $directive['status'], $status, $_SESSION['user_id']);
$logStmt->execute();
}
echo json_encode([
'success' => true,
'message' => 'Directive status updated successfully',
'directive' => [
'id' => $id,
'old_status' => $directive['status'],
'new_status' => $status,
'combination' => $directive['attribute1_name'] . ' = ' . $directive['choice1'] . ' + ' . $directive['attribute2_name'] . ' = ' . $directive['choice2']
]
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => $e->getMessage(),
'error_code' => 'DIRECTIVE_UPDATE_FAILED'
]);
}
-------------------- END OF FILE --------------------
### FILE 78: syndia.kreahealthcare.com/update_optimaize_db.php
- Type: PHP
- Size: 5.25 KB
- Path: syndia.kreahealthcare.com
- Name: update_optimaize_db.php
------------------------------------------------------------
OptimAIze Database Update";
echo "";
try {
$db = Database::getInstance();
echo "✅ Database connected successfully
";
// Check and add should_pause column to optimization_analysis_state
echo "Updating optimization_analysis_state table ";
$checkColumn = $db->query("SHOW COLUMNS FROM optimization_analysis_state LIKE 'should_pause'");
if ($checkColumn && $checkColumn->num_rows > 0) {
echo "ℹ️ Column 'should_pause' already exists
";
} else {
$addColumn = $db->query("ALTER TABLE optimization_analysis_state ADD COLUMN should_pause TINYINT(1) DEFAULT 0 AFTER is_running");
if ($addColumn) {
echo "✅ Added 'should_pause' column successfully
";
} else {
echo "❌ Failed to add 'should_pause' column: " . $db->getLastError() . "
";
}
}
// Verify all required columns exist
echo "Verifying Required Columns ";
$requiredColumns = [
'optimization_analysis_state' => ['total_combinations', 'processed_combinations', 'is_running', 'should_pause', 'started_at', 'completed_at', 'last_updated'],
'panel_directives' => ['llm_checked', 'is_impossible', 'llm_reasoning', 'status', 'updated_at']
];
foreach ($requiredColumns as $table => $columns) {
echo "Table: $table ";
foreach ($columns as $column) {
$checkResult = $db->query("SHOW COLUMNS FROM $table LIKE '$column'");
if ($checkResult && $checkResult->num_rows > 0) {
echo "✅ $column
";
} else {
echo "❌ $column (missing)
";
}
}
echo " ";
}
// Check current data status
echo "Current Data Status ";
$totalDirectives = $db->query("SELECT COUNT(*) as count FROM panel_directives")->fetch_assoc()['count'];
$checkedDirectives = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1")->fetch_assoc()['count'];
$impossibleDirectives = $db->query("SELECT COUNT(*) as count FROM panel_directives WHERE llm_checked = 1 AND is_impossible = 1")->fetch_assoc()['count'];
echo "📊 Total directives: " . number_format($totalDirectives) . "
";
echo "📊 Checked directives: " . number_format($checkedDirectives) . "
";
echo "📊 Impossible directives: " . number_format($impossibleDirectives) . "
";
if ($totalDirectives > 0) {
$progress = ($checkedDirectives / $totalDirectives) * 100;
echo "📊 Progress: " . number_format($progress, 1) . "%
";
}
// Reset any stuck analysis state
echo "Resetting Analysis State ";
$resetResult = $db->query("UPDATE optimization_analysis_state SET is_running = 0, should_pause = 0 WHERE is_running = 1");
if ($resetResult) {
echo "✅ Analysis state reset (any stuck processes stopped)
";
} else {
echo "⚠️ Could not reset analysis state
";
}
echo "Setup Complete! ";
echo "✅ Database is ready for the enhanced OptimAIze system
";
echo "ℹ️ You can now use the new OptimAIze page with start/pause functionality
";
echo "Next Steps: ";
echo "";
echo "Replace your current optimaize.php with the enhanced version ";
echo "Add the new analysis_control.php file ";
echo "Add the get_recent_combinations.php file ";
echo "Replace process_optimization_analysis.php with enhanced_process_optimization.php ";
echo "Update get_optimization_progress.php with the enhanced version ";
echo " ";
echo "📋 Performance Notes:
";
echo "";
echo "The new system processes 20 combinations per batch ";
echo "Uses parallel processing for up to 5 simultaneous GPT requests ";
echo "Should achieve 200-400 combinations per minute (vs previous ~12/minute) ";
echo "Includes automatic pause/resume functionality ";
echo "Shows only last 5 possible combinations and all impossible ones ";
echo " ";
} catch (Exception $e) {
echo "❌ Database Error: " . htmlspecialchars($e->getMessage()) . "
";
echo "Please check your database connection and try again.
";
}
?>
-------------------- END OF FILE --------------------
### FILE 79: syndia.kreahealthcare.com/update_question_order.php
- Type: PHP
- Size: 1.79 KB
- Path: syndia.kreahealthcare.com
- Name: update_question_order.php
------------------------------------------------------------
isLoggedIn()) {
throw new Exception('Unauthorized');
}
// Get input data
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['survey_id']) || !isset($input['question_order']) || !is_array($input['question_order'])) {
throw new Exception('Missing required parameters');
}
$surveyId = (int)$input['survey_id'];
$questionOrder = $input['question_order'];
// Verify user has access to this survey
$db = Database::getInstance();
$stmt = $db->prepare("SELECT id FROM surveys WHERE id = ? AND created_by = ?");
$stmt->bind_param('ii', $surveyId, $_SESSION['user_id']);
$stmt->execute();
if ($stmt->get_result()->num_rows === 0) {
throw new Exception('Access denied');
}
// Update question order
$db->query("START TRANSACTION");
$stmt = $db->prepare("UPDATE survey_questions SET question_order = ? WHERE id = ? AND survey_id = ?");
foreach ($questionOrder as $order => $questionId) {
$stmt->bind_param('iii', $order, $questionId, $surveyId);
if (!$stmt->execute()) {
throw new Exception("Failed to update question order");
}
}
$db->query("COMMIT");
echo json_encode([
'success' => true,
'message' => 'Question order updated successfully'
]);
} catch (Exception $e) {
if (isset($db) && $db->inTransaction()) {
$db->query("ROLLBACK");
}
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
?>
-------------------- END OF FILE --------------------
### FILE 80: syndia.kreahealthcare.com/users.php
- Type: PHP
- Size: 22.61 KB
- Path: syndia.kreahealthcare.com
- Name: users.php
------------------------------------------------------------
isLoggedIn() || !$auth->isAdmin()) {
redirectTo('dashboard.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
$error = '';
$success = '';
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'create') {
$fullName = sanitizeInput($_POST['full_name'] ?? '');
$email = sanitizeInput($_POST['email'] ?? '');
$phone = sanitizeInput($_POST['phone'] ?? '');
$whatsapp = sanitizeInput($_POST['whatsapp'] ?? '');
$password = $_POST['password'] ?? '';
$role = sanitizeInput($_POST['role'] ?? 'user');
if (empty($fullName) || empty($email) || empty($password)) {
$error = 'Please fill in all required fields.';
} elseif (!validateEmail($email)) {
$error = 'Please enter a valid email address.';
} else {
// Check if email already exists
$email_escaped = $db->escape($email);
$checkResult = $db->query("SELECT id FROM users WHERE email = '$email_escaped'");
if ($checkResult && $checkResult->num_rows > 0) {
$error = 'A user with this email already exists.';
} else {
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$fullName_escaped = $db->escape($fullName);
$phone_escaped = $db->escape($phone);
$whatsapp_escaped = $db->escape($whatsapp);
$role_escaped = $db->escape($role);
$sql = "INSERT INTO users (full_name, email, phone, whatsapp, password, role)
VALUES ('$fullName_escaped', '$email_escaped', '$phone_escaped', '$whatsapp_escaped', '$hashedPassword', '$role_escaped')";
if ($db->query($sql)) {
$success = 'User created successfully.';
} else {
$error = 'Error creating user: ' . $db->getLastError();
}
}
}
} elseif ($action === 'update') {
$userId = (int)$_POST['user_id'];
$fullName = sanitizeInput($_POST['full_name'] ?? '');
$email = sanitizeInput($_POST['email'] ?? '');
$phone = sanitizeInput($_POST['phone'] ?? '');
$whatsapp = sanitizeInput($_POST['whatsapp'] ?? '');
$role = sanitizeInput($_POST['role'] ?? 'user');
if (empty($fullName) || empty($email)) {
$error = 'Please fill in all required fields.';
} elseif (!validateEmail($email)) {
$error = 'Please enter a valid email address.';
} else {
$fullName_escaped = $db->escape($fullName);
$email_escaped = $db->escape($email);
$phone_escaped = $db->escape($phone);
$whatsapp_escaped = $db->escape($whatsapp);
$role_escaped = $db->escape($role);
$sql = "UPDATE users SET
full_name = '$fullName_escaped',
email = '$email_escaped',
phone = '$phone_escaped',
whatsapp = '$whatsapp_escaped',
role = '$role_escaped'
WHERE id = $userId";
if ($db->query($sql)) {
$success = 'User updated successfully.';
} else {
$error = 'Error updating user: ' . $db->getLastError();
}
}
} elseif ($action === 'delete') {
$userId = (int)$_POST['user_id'];
// Don't allow deleting yourself
if ($userId === (int)$_SESSION['user_id']) {
$error = 'You cannot delete your own account.';
} else {
$sql = "DELETE FROM users WHERE id = $userId";
if ($db->query($sql)) {
$success = 'User deleted successfully.';
} else {
$error = 'Error deleting user: ' . $db->getLastError();
}
}
}
}
// Get all users
$users = $db->query("SELECT * FROM users ORDER BY created_at DESC");
?>
Users |
-------------------- END OF FILE --------------------
### FILE 81: syndia.kreahealthcare.com/view_selection.php
- Type: PHP
- Size: 30.39 KB
- Path: syndia.kreahealthcare.com
- Name: view_selection.php
------------------------------------------------------------
isLoggedIn()) {
redirectTo('login.php');
}
$currentUser = $auth->getCurrentUser();
$db = Database::getInstance();
// Get selection ID from URL
$selection_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$selection_id) {
redirectTo('projects.php');
}
// Get selection details with project info
$stmt = $db->prepare("
SELECT s.*, p.project_id, p.title as project_title, p.client_name
FROM selections s
JOIN projects p ON s.project_id = p.id
WHERE s.id = ? AND p.created_by = ?
");
$stmt->bind_param('ii', $selection_id, $_SESSION['user_id']);
$stmt->execute();
$selection = $stmt->get_result()->fetch_assoc();
if (!$selection) {
redirectTo('projects.php');
}
// Get selection members count
$members_count = $db->query("SELECT COUNT(*) as count FROM selection_members WHERE selection_id = $selection_id")->fetch_assoc()['count'];
// Get selection members for display (paginated)
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$per_page = 50;
$offset = ($page - 1) * $per_page;
$members_query = $db->query("
SELECT sm.*, pd.attribute_values, pd.panelist_id
FROM selection_members sm
JOIN panel_data pd ON sm.panelist_id = pd.panelist_id
WHERE sm.selection_id = $selection_id
ORDER BY sm.created_at DESC
LIMIT $per_page OFFSET $offset
");
$members = [];
if ($members_query) {
while ($row = $members_query->fetch_assoc()) {
$members[] = $row;
}
}
$total_pages = ceil($members_count / $per_page);
// Get attributes for display
$attributes = $db->query("SELECT * FROM attributes ORDER BY name ASC");
// Handle messages
$error = isset($_SESSION['error_message']) ? $_SESSION['error_message'] : '';
$success = isset($_SESSION['success_message']) ? $_SESSION['success_message'] : '';
if (isset($_SESSION['error_message'])) unset($_SESSION['error_message']);
if (isset($_SESSION['success_message'])) unset($_SESSION['success_message']);
?>
View Selection |
Total Members
Selected panelists
Target Size
Requested sample size
Completion Rate
0 ?
round(($members_count / $selection['sample_size']) * 100, 1) : 0;
echo $completion_rate; ?>%
Target achievement
No Members Found
This selection doesn't have any members yet.
1): ?>
-------------------- END OF FILE --------------------
### FILE 82: syndia.kreahealthcare.com/.well-known/acme-challenge/dTZpZTVtazRsbGVqaHRqbDFjM3FrdTMycDA
- Type:
- Size: 79 B
- Path: syndia.kreahealthcare.com/.well-known/acme-challenge
- Name: dTZpZTVtazRsbGVqaHRqbDFjM3FrdTMycDA
------------------------------------------------------------
dTZpZTVtazRsbGVqaHRqbDFjM3FrdTMycDA.gLaCKdQb6MSBppFiuPb_-EfuesBPvYXYPleC7ZzQbck
-------------------- END OF FILE --------------------
### FILE 83: syndia.kreahealthcare.com/assets/js/integrity-check-script.js
- Type: JS
- Size: 33.99 KB
- Path: syndia.kreahealthcare.com/assets/js
- Name: integrity-check-script.js
------------------------------------------------------------
// Global variables
let integrityCheckInterval = null;
let directivesLoading = false;
// Integrity Check Functions
function startIntegrityCheck() {
console.log("Start button clicked"); // Debug log
const startBtn = document.getElementById('startCheckBtn');
const progressBar = document.getElementById('integrityProgressBar');
const progressText = document.getElementById('integrityProgressText');
startBtn.disabled = true;
progressText.textContent = 'Starting check...';
progressBar.style.width = '0%';
// Show a notification for debugging
showNotification('Attempting to start integrity check...', 'info');
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=start_integrity_check'
})
.then(response => {
console.log("Response status:", response.status); // Debug log
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Parsed data:", data); // Debug log
if (data.success) {
updateIntegrityCheckUI(true);
progressBar.classList.add('processing');
startProgressMonitoring();
showNotification('Integrity check started successfully', 'success');
} else {
throw new Error(data.message || 'Failed to start check');
}
})
.catch(error => {
console.error('Error starting check:', error);
progressText.textContent = 'Error: ' + error.message;
startBtn.disabled = false;
progressBar.classList.remove('processing');
showNotification('Error: ' + error.message, 'error');
});
}
function startProgressMonitoring() {
const progressBar = document.getElementById('integrityProgressBar');
const progressText = document.getElementById('integrityProgressText');
let failedAttempts = 0;
const maxFailedAttempts = 10;
const retryDelay = 3000; // 3 seconds between retries - increased to reduce server load
let isPhase1 = true; // Track which phase we're in
if (integrityCheckInterval) {
clearInterval(integrityCheckInterval);
}
// Add processing animation class
progressBar.classList.add('processing');
const checkProgress = async () => {
try {
const response = await fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache'
},
body: 'action=get_check_status'
});
if (response.status === 503) {
failedAttempts += 0.5; // Count 503s as half failures
console.log('Server busy, attempt: ' + failedAttempts);
return; // Continue monitoring without throwing error
}
if (!response.ok) {
throw new Error(`Server returned ${response.status}: ${response.statusText}`);
}
// Get raw text and try to parse
const text = await response.text();
let data;
try {
data = JSON.parse(text);
} catch (e) {
console.error("Failed to parse JSON response:", text);
failedAttempts++;
return; // Skip this update
}
if (data.success && data.status) {
// Reset failed attempts on success
failedAttempts = 0;
const status = data.status;
// Check for phase transition
if (data.phase_change || (status.status &&
(status.status.includes('Phase 2') || status.status.includes('Starting phase 2')))) {
if (isPhase1) {
isPhase1 = false;
// Phase transition notification
showNotification('Phase 1 complete. Starting Phase 2: Grouping anomalies into directives.', 'info');
// Reset progress bar for phase 2
progressBar.style.width = '0%';
progressText.textContent = 'Starting Phase 2: Grouping anomalies...';
}
}
const progress = (parseInt(status.processed_count) / parseInt(status.total_count) * 100) || 0;
// Update progress bar and text
progressBar.style.width = `${progress}%`;
progressText.textContent = status.status || `Processing: ${progress.toFixed(1)}%`;
// Check if the process is complete or stopped
if (!status.is_running || progress >= 100) {
clearInterval(integrityCheckInterval);
progressBar.classList.remove('processing');
if (progress >= 100) {
progressText.textContent = 'Check completed';
showNotification('Integrity check completed successfully.', 'success');
// Process Phase 2 before switching tabs
setTimeout(() => {
checkPhase2Status();
}, 1500);
}
}
// Update UI based on status
if (status.is_paused == '1') {
progressBar.classList.add('paused');
progressText.classList.add('paused');
updateIntegrityCheckUI(true, true);
} else if (status.status && status.status.includes('cooling')) {
progressBar.classList.add('cooling');
progressText.classList.add('cooling');
progressBar.classList.remove('paused');
progressText.classList.remove('paused');
} else {
progressBar.classList.remove('cooling');
progressText.classList.remove('cooling');
progressBar.classList.remove('paused');
progressText.classList.remove('paused');
}
}
} catch (error) {
console.error('Progress monitoring error:', error);
failedAttempts++;
if (failedAttempts >= maxFailedAttempts) {
// Reset counter and show warning but keep monitoring
failedAttempts = maxFailedAttempts / 2;
showNotification('Server is busy. Progress will continue in background.', 'warning');
}
}
};
// Initial check
checkProgress();
// Set up interval - check every 3 seconds
integrityCheckInterval = setInterval(checkProgress, retryDelay);
}
function checkPhase2Status() {
console.log("Checking Phase 2 status");
// Add a timeout counter
if (!window.phase2TimeoutCounter) {
window.phase2TimeoutCounter = 0;
}
window.phase2TimeoutCounter++;
// If we've been checking for too long (20 attempts), force completion
if (window.phase2TimeoutCounter > 20) {
console.log("Phase 2 taking too long, forcing completion");
window.phase2TimeoutCounter = 0;
switchTab('directives');
return;
}
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=process_anomaly_batch'
})
.then(response => {
if (!response.ok) {
console.log("Phase 2 status check response not OK:", response.status);
throw new Error(`Server returned ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Phase 2 processing response:", data);
if (data.success) {
if (data.status === 'completed') {
// All anomalies processed, load directives
console.log("Phase 2 complete, switching to directives tab");
window.phase2TimeoutCounter = 0; // Reset counter
switchTab('directives');
} else if (data.status === 'processing') {
// Update progress bar
const progressBar = document.getElementById('integrityProgressBar');
const progressText = document.getElementById('integrityProgressText');
if (progressBar && data.progress !== undefined) {
progressBar.style.width = `${data.progress}%`;
progressText.textContent = `Processing: ${data.processed} of ${data.total} anomalies (${data.progress}%)`;
}
// Continue processing
setTimeout(checkPhase2Status, 2000);
} else {
// Unknown status but successful, assume complete
console.log("Phase 2 unknown status, assuming complete");
window.phase2TimeoutCounter = 0; // Reset counter
switchTab('directives');
}
} else {
showNotification('Error processing anomalies: ' + (data.message || 'Unknown error'), 'error');
// Still continue after a delay
setTimeout(checkPhase2Status, 5000);
}
})
.catch(error => {
console.error("Error checking Phase 2 status:", error);
// Retry after a delay
setTimeout(checkPhase2Status, 5000);
});
}
function stopIntegrityCheck() {
console.log("Stop button clicked");
if (!confirm('Are you sure you want to stop the integrity check? This will terminate the process.')) {
return;
}
showNotification('Attempting to stop check...', 'info');
fetch('integrity_check_handler.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'action=stop'
})
.then(response => {
console.log("Stop response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Stop response data:", data);
if (data.success) {
if (integrityCheckInterval) {
clearInterval(integrityCheckInterval);
}
const progressBar = document.getElementById('integrityProgressBar');
progressBar.classList.remove('processing');
progressBar.classList.remove('cooling');
updateIntegrityCheckUI(false);
showNotification('Integrity check stopped.', 'info');
} else {
throw new Error(data.message || 'Failed to stop integrity check');
}
})
.catch(error => {
console.error('Error stopping check:', error);
showNotification('Failed to stop check: ' + error.message, 'error');
});
}
// Pause and Resume Functions
function pauseIntegrityCheck() {
console.log("Pause button clicked");
const pauseBtn = document.getElementById('pauseCheckBtn');
// If already paused, this is a resume action
if (pauseBtn.textContent.trim() === 'Resume') {
resumeIntegrityCheck();
return;
}
showNotification('Attempting to pause check...', 'info');
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'action=pause'
})
.then(response => {
console.log("Pause response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Pause response data:", data);
if (data.success) {
const progressBar = document.getElementById('integrityProgressBar');
const progressText = document.getElementById('integrityProgressText');
progressBar.classList.add('paused');
progressText.classList.add('paused');
progressText.textContent = 'Check paused';
pauseBtn.textContent = 'Resume';
showNotification('Integrity check paused.', 'info');
} else {
throw new Error(data.message || 'Failed to pause integrity check');
}
})
.catch(error => {
console.error('Error pausing check:', error);
showNotification('Failed to pause check: ' + error.message, 'error');
});
}
function resumeIntegrityCheck() {
console.log("Resume button clicked");
const pauseBtn = document.getElementById('pauseCheckBtn');
showNotification('Attempting to resume check...', 'info');
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'action=resume'
})
.then(response => {
console.log("Resume response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Resume response data:", data);
if (data.success) {
const progressBar = document.getElementById('integrityProgressBar');
const progressText = document.getElementById('integrityProgressText');
progressBar.classList.remove('paused');
progressText.classList.remove('paused');
progressText.textContent = 'Check resumed';
pauseBtn.textContent = 'Pause';
showNotification('Integrity check resumed.', 'info');
} else {
throw new Error(data.message || 'Failed to resume integrity check');
}
})
.catch(error => {
console.error('Error resuming check:', error);
showNotification('Failed to resume check: ' + error.message, 'error');
});
}
function updateIntegrityCheckUI(running, paused = false) {
const startBtn = document.getElementById('startCheckBtn');
const pauseBtn = document.getElementById('pauseCheckBtn');
const stopBtn = document.getElementById('stopCheckBtn');
const progressText = document.getElementById('integrityProgressText');
const progressBar = document.getElementById('integrityProgressBar');
if (running) {
startBtn.style.display = 'none';
pauseBtn.style.display = 'inline-block';
stopBtn.style.display = 'inline-block';
if (paused) {
pauseBtn.textContent = 'Resume';
progressText.textContent = 'Check paused';
progressBar.classList.add('paused');
progressText.classList.add('paused');
} else {
pauseBtn.textContent = 'Pause';
progressBar.classList.remove('paused');
progressText.classList.remove('paused');
if (!progressText.textContent.includes('%')) {
progressText.textContent = 'Processing...';
}
}
} else {
startBtn.style.display = 'inline-block';
pauseBtn.style.display = 'none';
stopBtn.style.display = 'none';
progressText.textContent = 'Ready to start integrity check';
}
}
// Directives Functions
function loadDirectives() {
// Prevent multiple simultaneous requests
if (directivesLoading) {
console.log("Already loading directives, request ignored");
return;
}
directivesLoading = true;
console.log("Loading directives");
const tableBody = document.getElementById('directivesTableBody');
if (!tableBody) {
console.error('Directives table body not found');
directivesLoading = false;
return;
}
tableBody.innerHTML = 'Loading directives... ';
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=get_directives'
})
.then(response => {
console.log("Get directives response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw directives response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
directivesLoading = false;
console.log("Directives data:", data);
if (!data.success) {
throw new Error(data.message || 'Failed to load directives');
}
if (!data.directives || data.directives.length === 0) {
tableBody.innerHTML = 'No directives found ';
return;
}
tableBody.innerHTML = data.directives.map(directive => `
${directive.id}
${directive.description}
${directive.record_count || 0}
${directive.status.charAt(0).toUpperCase() + directive.status.slice(1)}
${directive.last_resolved ? `
Last resolved: ${new Date(directive.last_resolved).toLocaleString()}
` : ''}
${directive.status !== 'approved' && directive.status !== 'resolved' ? `
Approve
` : ''}
${directive.status !== 'rejected' && directive.status !== 'resolved' ? `
Reject
` : ''}
Resolve
`).join('');
})
.catch(error => {
directivesLoading = false;
console.error('Error loading directives:', error);
tableBody.innerHTML = `Failed to load directives: ${error.message} `;
showNotification('Failed to load directives: ' + error.message, 'error');
});
}
function handleResolveAction(directiveId) {
console.log("Handling resolve action for directive:", directiveId);
showNotification('Analyzing affected records...', 'info');
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=check_affected_members&directive_id=${directiveId}`
})
.then(response => {
console.log("Check affected members response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Affected members data:", data);
if (!data.success) {
throw new Error(data.message || 'Failed to check affected members');
}
showResolveConfirmation(directiveId, data);
})
.catch(error => {
console.error('Error in handleResolveAction:', error);
showNotification(error.message, 'error');
});
}
function showResolveConfirmation(directiveId, data) {
// Create modal overlay if it doesn't exist
let overlay = document.querySelector('.modal-overlay');
if (!overlay) {
overlay = document.createElement('div');
overlay.className = 'modal-overlay';
document.body.appendChild(overlay);
}
overlay.innerHTML = `
Resolve Directive
${data.description}
This action will delete ${data.affected_count} panel members with this anomaly.
Cancel
Confirm Delete
`;
overlay.style.display = 'flex';
}
function closeResolveModal() {
const overlay = document.querySelector('.modal-overlay');
if (overlay) {
overlay.style.display = 'none';
}
}
function applyResolve(directiveId) {
console.log("Applying resolve for directive:", directiveId);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=apply_resolve&directive_id=${directiveId}`
})
.then(response => {
console.log("Apply resolve response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Apply resolve data:", data);
if (data.success) {
closeResolveModal();
showNotification(`Anomaly resolved successfully. ${data.affected_count} records deleted.`, 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to resolve directive');
}
})
.catch(error => {
console.error('Error in applyResolve:', error);
showNotification('Failed to resolve directive: ' + error.message, 'error');
});
}
function submitDirective() {
const input = document.getElementById('directiveInput');
const description = input.value.trim();
if (!description) {
showNotification('Please enter a directive description', 'error');
return;
}
console.log("Submitting new directive:", description);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=add_directive&description=${encodeURIComponent(description)}`
})
.then(response => {
console.log("Add directive response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Add directive data:", data);
if (data.success) {
input.value = '';
showNotification('Directive added successfully', 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to add directive');
}
})
.catch(error => {
console.error('Error in submitDirective:', error);
showNotification('Failed to add directive: ' + error.message, 'error');
});
}
function handleDirectiveAction(id, action) {
console.log(`Handling ${action} action for directive:`, id);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=${action}_directive&directive_id=${id}`
})
.then(response => {
console.log(`${action} directive response status:`, response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log(`${action} directive data:`, data);
if (data.success) {
showNotification(`Directive ${action}ed successfully`, 'success');
loadDirectives(); // Reload the directives list
} else {
throw new Error(data.message || `Failed to ${action} directive`);
}
})
.catch(error => {
console.error(`Error in ${action} directive:`, error);
showNotification(error.message, 'error');
});
}
// Helper Functions
function switchTab(tab) {
console.log("Switching to tab:", tab);
// Find the tab elements
const tabs = document.querySelectorAll('.optimaize-tab');
const contents = document.querySelectorAll('.optimaize-content');
// Deactivate all tabs
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.style.display = 'none');
// Activate the requested tab
let tabElement = null;
for (const t of tabs) {
if (t.getAttribute('data-tab') === tab ||
t.textContent.toLowerCase().includes(tab.toLowerCase())) {
tabElement = t;
break;
}
}
if (tabElement) {
tabElement.classList.add('active');
}
// Show the corresponding content
let contentElement = null;
if (tab === 'integrity') {
contentElement = document.getElementById('integrityCheckContent');
} else if (tab === 'directives') {
contentElement = document.getElementById('directivesContent');
}
if (contentElement) {
contentElement.style.display = 'block';
// Load directives when switching to that tab
if (tab === 'directives') {
loadDirectives();
}
}
}
// Utility function to show notifications
function showNotification(message, type = 'success') {
console.log(`Notification (${type}):`, message);
const container = document.getElementById('notificationContainer');
if (!container) {
// Create container if it doesn't exist
const newContainer = document.createElement('div');
newContainer.id = 'notificationContainer';
newContainer.style.position = 'fixed';
newContainer.style.top = '20px';
newContainer.style.right = '20px';
newContainer.style.zIndex = '9999';
document.body.appendChild(newContainer);
// Use the newly created container
showNotification(message, type);
return;
}
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.style.padding = '10px 15px';
notification.style.margin = '0 0 10px 0';
notification.style.borderRadius = '4px';
notification.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.3s';
// Set background color based on type
if (type === 'success') {
notification.style.backgroundColor = '#4CAF50';
notification.style.color = 'white';
} else if (type === 'error') {
notification.style.backgroundColor = '#F44336';
notification.style.color = 'white';
} else if (type === 'warning') {
notification.style.backgroundColor = '#FF9800';
notification.style.color = 'white';
} else if (type === 'info') {
notification.style.backgroundColor = '#2196F3';
notification.style.color = 'white';
}
const icon = document.createElement('span');
icon.className = 'notification-icon';
icon.style.marginRight = '10px';
icon.textContent = type === 'success' ? '✓' : type === 'warning' ? '⚠' : type === 'info' ? 'ℹ' : '⨉';
const text = document.createElement('span');
text.className = 'notification-message';
text.textContent = message;
notification.appendChild(icon);
notification.appendChild(text);
container.appendChild(notification);
// Show notification with a small delay
setTimeout(() => {
notification.style.opacity = '1';
}, 10);
// Hide and remove after 5 seconds
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 300);
}, 5000);
}
// Initialize event handlers
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM loaded, initializing integrity check handlers");
// Setup integrity check button handlers
const startCheckBtn = document.getElementById('startCheckBtn');
if (startCheckBtn) {
startCheckBtn.addEventListener('click', startIntegrityCheck);
console.log("Start button handler attached");
} else {
console.error("Start button not found");
}
const pauseCheckBtn = document.getElementById('pauseCheckBtn');
if (pauseCheckBtn) {
pauseCheckBtn.addEventListener('click', pauseIntegrityCheck);
console.log("Pause button handler attached");
} else {
console.error("Pause button not found");
}
const stopCheckBtn = document.getElementById('stopCheckBtn');
if (stopCheckBtn) {
stopCheckBtn.addEventListener('click', stopIntegrityCheck);
console.log("Stop button handler attached");
} else {
console.error("Stop button not found");
}
// Setup tabs
const integrityTab = document.querySelector('.optimaize-tab[data-tab="integrity"]');
if (integrityTab) {
integrityTab.addEventListener('click', (e) => {
console.log("Integrity tab clicked");
e.preventDefault();
switchTab('integrity');
});
console.log("Integrity tab handler attached");
} else {
console.warn("Integrity tab not found");
}
const directivesTab = document.querySelector('.optimaize-tab[data-tab="directives"]');
if (directivesTab) {
directivesTab.addEventListener('click', (e) => {
console.log("Directives tab clicked");
e.preventDefault();
switchTab('directives');
});
console.log("Directives tab handler attached");
} else {
console.warn("Directives tab not found");
}
// Load integrity tab by default
if (document.querySelector('.optimaize-section') &&
document.querySelector('.optimaize-section').style.display === 'block') {
console.log("Initializing default tab: integrity");
switchTab('integrity');
}
console.log("Initialization complete");
});
-------------------- END OF FILE --------------------
### FILE 84: syndia.kreahealthcare.com/assets/js/panel_alignment.js
- Type: JS
- Size: 0 B
- Path: syndia.kreahealthcare.com/assets/js
- Name: panel_alignment.js
------------------------------------------------------------
-------------------- END OF FILE --------------------
### FILE 85: syndia.kreahealthcare.com/assets/js/panel_directives.js
- Type: JS
- Size: 19.98 KB
- Path: syndia.kreahealthcare.com/assets/js
- Name: panel_directives.js
------------------------------------------------------------
// Wrap the entire code in an IIFE (Immediately Invoked Function Expression)
// to create a private scope and avoid global variable conflicts
(function() {
// Use a local variable instead of global
let directivesLoadingState = false;
// Expose necessary functions to window/global scope
window.loadDirectives = loadDirectives;
window.handleDirectiveAction = handleDirectiveAction;
window.deleteDirective = deleteDirective;
window.loadAttributeChoices = loadAttributeChoices;
window.switchTab = switchTab;
window.submitDirective = submitDirective;
// Directives Functions
function loadDirectives() {
// Prevent multiple simultaneous requests
if (directivesLoadingState) {
console.log("Already loading directives, request ignored");
return;
}
directivesLoadingState = true;
console.log("Loading directives");
const tableBody = document.getElementById('directivesTableBody');
if (!tableBody) {
console.error('Directives table body not found');
directivesLoadingState = false;
return;
}
tableBody.innerHTML = 'Loading directives... ';
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=get_directives'
})
.then(response => {
console.log("Get directives response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw directives response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
directivesLoadingState = false;
console.log("Directives data:", data);
if (!data.success) {
throw new Error(data.message || 'Failed to load directives');
}
if (!data.directives || data.directives.length === 0) {
tableBody.innerHTML = 'No directives found ';
return;
}
// Group directives by attributes to identify sets created from multiple selections
const directiveSets = groupDirectivesByAttributes(data.directives);
// Build HTML for each directive
let html = '';
for (const directive of data.directives) {
// See if this directive is part of a set (created from multiple selections)
const setKey = `${directive.attribute1_id}_${directive.attribute2_id}`;
const setInfo = directiveSets[setKey];
const isPartOfSet = setInfo && (setInfo.attr1Choices.length > 1 || setInfo.attr2Choices.length > 1);
const setDescription = isPartOfSet ?
`(Part of a set: ${setInfo.attr1Choices.length} × ${setInfo.attr2Choices.length} combinations)` : '';
// Create the row HTML
html += `
${directive.id}
${directive.attribute1_name}: ${directive.choice1}
${isPartOfSet ? `${setDescription}
` : ''}
${directive.attribute2_name}: ${directive.choice2}
${directive.status.charAt(0).toUpperCase() + directive.status.slice(1)}
${directive.status === 'pending' ? `
Approve
` : `
Revoke
`}
Delete
`;
}
tableBody.innerHTML = html;
// Add some CSS for set info
addSetInfoStyles();
})
.catch(error => {
directivesLoadingState = false;
console.error('Error loading directives:', error);
tableBody.innerHTML = `Failed to load directives: ${error.message} `;
showNotification('Failed to load directives: ' + error.message, 'error');
});
}
function groupDirectivesByAttributes(directives) {
const sets = {};
for (const directive of directives) {
const key = `${directive.attribute1_id}_${directive.attribute2_id}`;
if (!sets[key]) {
sets[key] = {
attribute1_id: directive.attribute1_id,
attribute2_id: directive.attribute2_id,
attribute1_name: directive.attribute1_name,
attribute2_name: directive.attribute2_name,
attr1Choices: [],
attr2Choices: []
};
}
// Add choices if they don't exist in the array
if (!sets[key].attr1Choices.includes(directive.choice1)) {
sets[key].attr1Choices.push(directive.choice1);
}
if (!sets[key].attr2Choices.includes(directive.choice2)) {
sets[key].attr2Choices.push(directive.choice2);
}
}
return sets;
}
function addSetInfoStyles() {
// Check if the styles are already added
if (document.getElementById('set-info-styles')) return;
const style = document.createElement('style');
style.id = 'set-info-styles';
style.textContent = `
.set-info {
font-size: 0.75rem;
color: var(--gray-500);
margin-top: 0.25rem;
font-style: italic;
}
`;
document.head.appendChild(style);
}
function submitDirective() {
const attribute1Select = document.getElementById('attribute1');
const attribute2Select = document.getElementById('attribute2');
const choice1Select = document.getElementById('choice1');
const choice2Select = document.getElementById('choice2');
if (!attribute1Select.value || !attribute2Select.value || !choice1Select.value || !choice2Select.value) {
showNotification('Please select all fields', 'error');
return;
}
if (attribute1Select.value === attribute2Select.value) {
showNotification('Please select two different attributes', 'error');
return;
}
const directiveData = {
attribute1_id: attribute1Select.value,
attribute2_id: attribute2Select.value,
choice1: choice1Select.value,
choice2: choice2Select.value
};
console.log("Submitting new directive:", directiveData);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=add_directive&data=${encodeURIComponent(JSON.stringify(directiveData))}`
})
.then(response => {
console.log("Add directive response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Add directive data:", data);
if (data.success) {
// Reset form
attribute1Select.value = '';
attribute2Select.value = '';
choice1Select.innerHTML = 'Select choice ';
choice2Select.innerHTML = 'Select choice ';
showNotification('Directive added successfully', 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to add directive');
}
})
.catch(error => {
console.error('Error in submitDirective:', error);
showNotification('Failed to add directive: ' + error.message, 'error');
});
}
function handleDirectiveAction(id, action) {
console.log(`Handling ${action} action for directive:`, id);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=${action}_directive&directive_id=${id}`
})
.then(response => {
console.log(`${action} directive response status:`, response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log(`${action} directive data:`, data);
if (data.success) {
showNotification(`Directive ${action === 'approve' ? 'approved' : 'revoked'} successfully`, 'success');
loadDirectives(); // Reload the directives list
} else {
throw new Error(data.message || `Failed to ${action} directive`);
}
})
.catch(error => {
console.error(`Error in ${action} directive:`, error);
showNotification(error.message, 'error');
});
}
function deleteDirective(id) {
if (!confirm('Are you sure you want to delete this directive?')) {
return;
}
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=delete_directive&directive_id=${id}`
})
.then(response => {
console.log("Delete directive response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text);
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Delete directive data:", data);
if (data.success) {
showNotification('Directive deleted successfully', 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to delete directive');
}
})
.catch(error => {
console.error('Error in deleteDirective:', error);
showNotification(error.message, 'error');
});
}
// Load choices for the selected attribute
function loadAttributeChoices(attributeId, targetSelectId) {
if (!attributeId) {
document.getElementById(targetSelectId).innerHTML = 'Select choice ';
return;
}
fetch('get_attribute_choices.php?attribute_id=' + attributeId)
.then(response => response.json())
.then(data => {
if (data.success) {
const select = document.getElementById(targetSelectId);
select.innerHTML = 'Select choice ';
data.choices.forEach(choice => {
const option = document.createElement('option');
option.value = choice;
option.textContent = choice;
select.appendChild(option);
});
} else {
console.error('Error loading choices:', data.message);
showNotification('Error loading choices: ' + data.message, 'error');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error loading choices', 'error');
});
}
// Helper Functions
function switchTab(tab) {
console.log("Switching to tab:", tab);
// Find the tab elements
const tabs = document.querySelectorAll('.optimaize-tab');
const contents = document.querySelectorAll('.optimaize-content');
// Deactivate all tabs
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.style.display = 'none');
// Activate the requested tab
let tabElement = null;
for (const t of tabs) {
if (t.getAttribute('data-tab') === tab ||
t.textContent.toLowerCase().includes(tab.toLowerCase())) {
tabElement = t;
break;
}
}
if (tabElement) {
tabElement.classList.add('active');
}
// Show the corresponding content
let contentElement = null;
if (tab === 'directives') {
contentElement = document.getElementById('directivesContent');
}
if (contentElement) {
contentElement.style.display = 'block';
// Load directives when switching to that tab
if (tab === 'directives') {
loadDirectives();
}
}
}
// Utility function to show notifications
function showNotification(message, type = 'success') {
console.log(`Notification (${type}):`, message);
const container = document.getElementById('notificationContainer');
if (!container) {
// Create container if it doesn't exist
const newContainer = document.createElement('div');
newContainer.id = 'notificationContainer';
newContainer.style.position = 'fixed';
newContainer.style.top = '20px';
newContainer.style.right = '20px';
newContainer.style.zIndex = '9999';
document.body.appendChild(newContainer);
// Use the newly created container
showNotification(message, type);
return;
}
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.style.padding = '10px 15px';
notification.style.margin = '0 0 10px 0';
notification.style.borderRadius = '4px';
notification.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.3s';
// Set background color based on type
if (type === 'success') {
notification.style.backgroundColor = '#4CAF50';
notification.style.color = 'white';
} else if (type === 'error') {
notification.style.backgroundColor = '#F44336';
notification.style.color = 'white';
} else if (type === 'warning') {
notification.style.backgroundColor = '#FF9800';
notification.style.color = 'white';
} else if (type === 'info') {
notification.style.backgroundColor = '#2196F3';
notification.style.color = 'white';
}
const icon = document.createElement('span');
icon.className = 'notification-icon';
icon.style.marginRight = '10px';
icon.textContent = type === 'success' ? '✓' : type === 'warning' ? '⚠' : type === 'info' ? 'ℹ' : '⨉';
const text = document.createElement('span');
text.className = 'notification-message';
text.textContent = message;
notification.appendChild(icon);
notification.appendChild(text);
container.appendChild(notification);
// Show notification with a small delay
setTimeout(() => {
notification.style.opacity = '1';
}, 10);
// Hide and remove after 5 seconds
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 300);
}, 5000);
}
// Initialize event handlers
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM loaded, initializing directive handlers");
// Setup tabs
const directivesTab = document.querySelector('.optimaize-tab[data-tab="directives"]');
if (directivesTab) {
directivesTab.addEventListener('click', (e) => {
console.log("Directives tab clicked");
e.preventDefault();
switchTab('directives');
});
console.log("Directives tab handler attached");
} else {
console.warn("Directives tab not found");
}
// Setup attribute selection change handlers
const attribute1Select = document.getElementById('attribute1');
const attribute2Select = document.getElementById('attribute2');
if (attribute1Select) {
attribute1Select.addEventListener('change', function() {
loadAttributeChoices(this.value, 'choice1');
});
}
if (attribute2Select) {
attribute2Select.addEventListener('change', function() {
loadAttributeChoices(this.value, 'choice2');
});
}
// Load directives by default
if (document.querySelector('.optimaize-section') &&
document.querySelector('.optimaize-section').style.display === 'block') {
console.log("Loading directives by default");
loadDirectives();
}
console.log("Directive initialization complete");
});
})();
-------------------- END OF FILE --------------------
### FILE 86: syndia.kreahealthcare.com/includes/auth.php
- Type: PHP
- Size: 2.36 KB
- Path: syndia.kreahealthcare.com/includes
- Name: auth.php
------------------------------------------------------------
db = Database::getInstance();
}
public function login($email, $password) {
try {
error_log("Login attempt for: " . $email); // Debug log
$email = $this->db->escape($email);
$sql = "SELECT * FROM users WHERE email = '$email'";
$result = $this->db->query($sql);
error_log("Query executed: " . $sql); // Debug log
if ($result && $result->num_rows > 0) {
$user = $result->fetch_assoc();
// Debug logs
error_log("User found: " . print_r($user, true));
error_log("Stored hash: " . $user['password']);
error_log("Input password: " . $password);
error_log("Password verify result: " . (password_verify($password, $user['password']) ? 'true' : 'false'));
if (password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_role'] = $user['role'];
$_SESSION['user_name'] = $user['full_name'];
error_log("Login successful for user: " . $user['full_name']);
return true;
}
}
error_log("Login failed for email: " . $email);
return false;
} catch (Exception $e) {
error_log("Login error: " . $e->getMessage());
return false;
}
}
public function isLoggedIn() {
return isset($_SESSION['user_id']);
}
public function isAdmin() {
return isset($_SESSION['user_role']) && $_SESSION['user_role'] === 'admin';
}
public function getCurrentUser() {
if (!$this->isLoggedIn()) {
return null;
}
$userId = (int)$_SESSION['user_id'];
$sql = "SELECT * FROM users WHERE id = $userId";
$result = $this->db->query($sql);
return $result ? $result->fetch_assoc() : null;
}
public function logout() {
$_SESSION = array();
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-3600, '/');
}
session_destroy();
return true;
}
}
-------------------- END OF FILE --------------------
### FILE 87: syndia.kreahealthcare.com/includes/config.php
- Type: PHP
- Size: 5.25 KB
- Path: syndia.kreahealthcare.com/includes
- Name: config.php
------------------------------------------------------------
'API rate limit exceeded. Please wait and try again.',
'quota_exceeded' => 'OpenAI quota exceeded. Please check your billing.',
'invalid_request' => 'Invalid request to GPT API.',
'auth_error' => 'Authentication failed. Check API key.',
'network_error' => 'Network error. Check internet connection.',
'server_error' => 'OpenAI server error. Try again later.',
'unknown_error' => 'Unknown error occurred.'
]);
// Cost tracking files
define('COST_LOG_FILE', __DIR__ . '/../logs/cost_tracking.log');
define('DAILY_COST_FILE', __DIR__ . '/../logs/daily_cost.json');
// Debug logging
define('DEBUG_RATE_LIMITS', true);
define('RATE_LIMIT_LOG_FILE', __DIR__ . '/../logs/rate_limit_debug.log');
// Ensure logs directory exists
if (!$is_cli) {
$log_dir = __DIR__ . '/../logs';
if (!is_dir($log_dir)) {
@mkdir($log_dir, 0755, true);
}
// Log optimization mode activation
error_log("Syndia: Optimized for OpenAI Tier 1 - Using gpt-4o-mini with 120 RPM");
}
// *** MISSING CONSTANTS ADDED ***
// Cost estimation constants (gpt-4o-mini pricing)
define('GPT4OMINI_COST_PER_1K_INPUT_TOKENS', 0.000150); // $0.00015 per 1K input tokens
define('GPT4OMINI_COST_PER_1K_OUTPUT_TOKENS', 0.000600); // $0.0006 per 1K output tokens
// Legacy constants for backward compatibility
define('GPT35_COST_PER_1K_TOKENS', 0.002); // $0.002 per 1K tokens (GPT-3.5)
define('GPT4_COST_PER_1K_TOKENS', 0.030); // $0.03 per 1K tokens (GPT-4)
// Token estimation constants
define('AVERAGE_INPUT_TOKENS_PER_REQUEST', 150); // Conservative estimate
define('AVERAGE_OUTPUT_TOKENS_PER_REQUEST', 50); // Conservative estimate
define('AVERAGE_TOKENS_PER_REQUEST', 200); // Total average
// Performance tracking
define('ENABLE_PERFORMANCE_TRACKING', true);
define('PERFORMANCE_LOG_FILE', __DIR__ . '/../logs/performance.log');
?>
-------------------- END OF FILE --------------------
### FILE 88: syndia.kreahealthcare.com/includes/db.php
- Type: PHP
- Size: 1.28 KB
- Path: syndia.kreahealthcare.com/includes
- Name: db.php
------------------------------------------------------------
connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($this->connection->connect_error) {
throw new Exception("Connection failed: " . $this->connection->connect_error);
}
$this->connection->set_charset("utf8mb4");
} catch (Exception $e) {
die("Database connection failed: " . $e->getMessage());
}
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new Database();
}
return self::$instance;
}
public function query($sql) {
return $this->connection->query($sql);
}
public function prepare($sql) {
return $this->connection->prepare($sql);
}
public function escape($value) {
return $this->connection->real_escape_string($value);
}
public function getLastError() {
return $this->connection->error;
}
public function getLastInsertId() {
return $this->connection->insert_id;
}
public function getConnection() {
return $this->connection;
}
}
-------------------- END OF FILE --------------------
### FILE 89: syndia.kreahealthcare.com/includes/functions.php
- Type: PHP
- Size: 999 B
- Path: syndia.kreahealthcare.com/includes
- Name: functions.php
------------------------------------------------------------
';
echo 'window.location.href="' . rtrim(SITE_URL, '/') . '/' . ltrim($path, '/') . '";';
echo '';
echo '';
echo ' ';
echo ' ';
exit();
}
}
function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL);
}
function validatePhone($phone) {
return preg_match('/^[0-9]{10}$/', $phone);
}
function sanitizeInput($input) {
return htmlspecialchars(strip_tags(trim($input)));
}
function checkPageAccess() {
$auth = new Auth();
if (!$auth->isLoggedIn()) {
redirectTo('login.php');
}
}
-------------------- END OF FILE --------------------
### FILE 90: syndia.kreahealthcare.com/includes/GptHelper.php
- Type: PHP
- Size: 20.78 KB
- Path: syndia.kreahealthcare.com/includes
- Name: GptHelper.php
------------------------------------------------------------
date('Y-m-d'),
'cost' => self::$dailyCost,
'updated_at' => date('Y-m-d H:i:s')
];
@file_put_contents(self::$dailyCostFile, json_encode($costData), LOCK_EX);
}
}
private static function trackCost($usage) {
if (!defined('ENABLE_COST_TRACKING') || !ENABLE_COST_TRACKING || !$usage) {
return;
}
$promptTokens = $usage['prompt_tokens'] ?? 0;
$completionTokens = $usage['completion_tokens'] ?? 0;
$totalTokens = $usage['total_tokens'] ?? ($promptTokens + $completionTokens);
// Calculate cost based on model - using safe constants
$model = defined('GPT_MODEL') ? GPT_MODEL : 'gpt-4o-mini';
// Use appropriate pricing based on model
if (strpos($model, 'gpt-4o-mini') !== false) {
// Use gpt-4o-mini pricing if available
if (defined('GPT4OMINI_COST_PER_1K_INPUT_TOKENS') && defined('GPT4OMINI_COST_PER_1K_OUTPUT_TOKENS')) {
$inputCost = ($promptTokens / 1000) * GPT4OMINI_COST_PER_1K_INPUT_TOKENS;
$outputCost = ($completionTokens / 1000) * GPT4OMINI_COST_PER_1K_OUTPUT_TOKENS;
$requestCost = $inputCost + $outputCost;
} else {
// Fallback pricing for gpt-4o-mini
$requestCost = ($totalTokens / 1000) * 0.000375; // Average of input/output
}
} elseif (strpos($model, 'gpt-3.5') !== false) {
$costPer1kTokens = defined('GPT35_COST_PER_1K_TOKENS') ? GPT35_COST_PER_1K_TOKENS : 0.002;
$requestCost = ($totalTokens / 1000) * $costPer1kTokens;
} elseif (strpos($model, 'gpt-4') !== false) {
$costPer1kTokens = defined('GPT4_COST_PER_1K_TOKENS') ? GPT4_COST_PER_1K_TOKENS : 0.030;
$requestCost = ($totalTokens / 1000) * $costPer1kTokens;
} else {
// Default to gpt-4o-mini pricing
$requestCost = ($totalTokens / 1000) * 0.000375;
}
self::$dailyCost += $requestCost;
self::costLog("Request cost: $" . number_format($requestCost, 4) .
" (Tokens: $totalTokens, Model: $model, Daily total: $" .
number_format(self::$dailyCost, 4) . ")");
self::saveDailyCost();
return $requestCost;
}
private static function loadCache() {
if (file_exists(self::$cacheFile)) {
$cached = @json_decode(file_get_contents(self::$cacheFile), true);
if (is_array($cached)) {
self::$combinationCache = $cached;
self::debugLog("Loaded " . count(self::$combinationCache) . " cached combinations");
}
}
}
private static function saveCache() {
if (defined('ENABLE_COMBINATION_CACHE') && ENABLE_COMBINATION_CACHE) {
$maxEntries = defined('MAX_CACHE_ENTRIES') ? MAX_CACHE_ENTRIES : 50000;
// Limit cache size
if (count(self::$combinationCache) > $maxEntries) {
self::$combinationCache = array_slice(self::$combinationCache, -$maxEntries, null, true);
}
@file_put_contents(self::$cacheFile, json_encode(self::$combinationCache), LOCK_EX);
}
}
private static function enforceRateLimit($isOptimAIze = false) {
self::init();
// Use OptimAIze-specific limits if applicable
$requestsPerMinute = $isOptimAIze && defined('OPTIMAIZE_REQUESTS_PER_MINUTE') ?
OPTIMAIZE_REQUESTS_PER_MINUTE :
(defined('GPT_REQUESTS_PER_MINUTE') ? GPT_REQUESTS_PER_MINUTE : 60);
$currentTime = time();
// Reset window if a minute has passed
if ($currentTime - self::$windowStartTime >= 60) {
self::$windowStartTime = $currentTime;
self::$requestCount = 0;
self::debugLog("Rate limit window reset. New window started. Requests per minute limit: $requestsPerMinute");
}
// Check if we've hit the rate limit
if (self::$requestCount >= $requestsPerMinute) {
$waitTime = 60 - ($currentTime - self::$windowStartTime) + 5; // Add 5 second buffer
self::debugLog("Rate limit reached ($requestsPerMinute/$requestsPerMinute). Waiting $waitTime seconds...");
sleep($waitTime);
// Reset after waiting
self::$windowStartTime = time();
self::$requestCount = 0;
}
// Ensure minimum time between requests
$minInterval = 60 / $requestsPerMinute;
$timeSinceLastRequest = $currentTime - self::$lastRequestTime;
if ($timeSinceLastRequest < $minInterval) {
$waitTime = ceil($minInterval - $timeSinceLastRequest);
self::debugLog("Enforcing minimum interval: waiting $waitTime seconds");
sleep($waitTime);
}
self::$lastRequestTime = time();
self::$requestCount++;
self::debugLog("Request #" . self::$requestCount . " in current window");
}
public static function getRateLimitStatus($isOptimAIze = false) {
self::init();
$requestsPerMinute = $isOptimAIze && defined('OPTIMAIZE_REQUESTS_PER_MINUTE') ?
OPTIMAIZE_REQUESTS_PER_MINUTE :
(defined('GPT_REQUESTS_PER_MINUTE') ? GPT_REQUESTS_PER_MINUTE : 60);
$currentTime = time();
// Reset window if a minute has passed
if ($currentTime - self::$windowStartTime >= 60) {
self::$windowStartTime = $currentTime;
self::$requestCount = 0;
}
$canMakeRequest = self::$requestCount < $requestsPerMinute;
$cooldownRemaining = $canMakeRequest ? 0 : (60 - ($currentTime - self::$windowStartTime));
return [
'can_make_request' => $canMakeRequest,
'requests_made' => self::$requestCount,
'requests_limit' => $requestsPerMinute,
'cooldown_remaining' => $cooldownRemaining,
'window_start' => self::$windowStartTime,
'rate_limit_hits' => self::$rateLimitHits,
'daily_cost' => self::$dailyCost,
'cost_limit' => defined('MAX_DAILY_COST') ? MAX_DAILY_COST : 0
];
}
public static function resetRateLimit() {
self::$requestCount = 0;
self::$windowStartTime = time();
self::$lastRequestTime = 0;
self::$rateLimitHits = 0;
self::debugLog("Rate limit counters reset");
}
public static function makeRequest($messages, $model = null, $temperature = null, $isOptimAIze = false) {
self::init();
// Check daily cost limit before making request
if (defined('ENABLE_COST_TRACKING') && ENABLE_COST_TRACKING &&
defined('MAX_DAILY_COST') && self::$dailyCost >= MAX_DAILY_COST) {
return [
'success' => false,
'error' => 'Daily cost limit reached ($' . number_format(MAX_DAILY_COST, 2) . '). Processing stopped.',
'response' => null,
'cost_limited' => true
];
}
$maxRetries = defined('GPT_MAX_RETRIES') ? GPT_MAX_RETRIES : 3;
$retryDelay = defined('GPT_RETRY_DELAY') ? GPT_RETRY_DELAY : 15;
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
try {
// Enforce rate limiting before each attempt
self::enforceRateLimit($isOptimAIze);
// Use default values if not provided
$model = $model ?? (defined('GPT_MODEL') ? GPT_MODEL : 'gpt-4o-mini');
$temperature = $temperature ?? (defined('GPT_TEMPERATURE') ? GPT_TEMPERATURE : 0.1);
$data = [
'model' => $model,
'messages' => $messages,
'max_tokens' => defined('GPT_MAX_TOKENS') ? GPT_MAX_TOKENS : 150,
'temperature' => $temperature,
'top_p' => 1,
'frequency_penalty' => 0,
'presence_penalty' => 0
];
self::debugLog("Making OpenAI API request (attempt $attempt/$maxRetries, model: $model)");
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => defined('GPT_API_ENDPOINT') ? GPT_API_ENDPOINT : 'https://api.openai.com/v1/chat/completions',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . (defined('OPENAI_API_KEY') ? OPENAI_API_KEY : '')
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
throw new Exception("cURL error: $curlError");
}
$responseData = json_decode($response, true);
if ($httpCode === 200 && isset($responseData['choices'][0]['message']['content'])) {
$responseText = trim($responseData['choices'][0]['message']['content']);
// Track cost if usage data is available
if (isset($responseData['usage'])) {
self::trackCost($responseData['usage']);
}
self::debugLog("API request successful (attempt $attempt)");
return [
'success' => true,
'response' => $responseText,
'model_used' => $model,
'daily_cost' => self::$dailyCost,
'usage' => $responseData['usage'] ?? null
];
} elseif ($httpCode === 429) {
self::$rateLimitHits++;
$retryAfter = 60; // Default wait time
if (isset($responseData['error']['message']) && preg_match('/retry after (\d+)/', $responseData['error']['message'], $matches)) {
$retryAfter = (int)$matches[1];
}
self::debugLog("Rate limit hit (attempt $attempt). Waiting $retryAfter seconds...");
if ($attempt < $maxRetries) {
sleep($retryAfter);
continue;
} else {
return [
'success' => false,
'error' => 'Rate limit exceeded. Please try again later.',
'response' => null
];
}
} else {
$errorMessage = isset($responseData['error']['message']) ?
$responseData['error']['message'] :
"HTTP $httpCode: Unknown error";
self::debugLog("API error (attempt $attempt): $errorMessage");
if ($attempt < $maxRetries) {
sleep($retryDelay);
continue;
} else {
return [
'success' => false,
'error' => $errorMessage,
'response' => null
];
}
}
} catch (Exception $e) {
self::debugLog("Exception (attempt $attempt): " . $e->getMessage());
if ($attempt < $maxRetries) {
sleep($retryDelay);
continue;
} else {
return [
'success' => false,
'error' => $e->getMessage(),
'response' => null
];
}
}
}
return [
'success' => false,
'error' => 'Max retries exceeded',
'response' => null
];
}
public static function analyzeCombination($attr1, $choice1, $attr2, $choice2) {
self::init();
// Check cache first
$cacheKey = strtolower("$attr1|$choice1|$attr2|$choice2");
if (defined('ENABLE_COMBINATION_CACHE') && ENABLE_COMBINATION_CACHE &&
isset(self::$combinationCache[$cacheKey])) {
$cached = self::$combinationCache[$cacheKey];
// Check cache expiry
$expiryHours = defined('CACHE_EXPIRY_HOURS') ? CACHE_EXPIRY_HOURS : 24;
if (isset($cached['timestamp']) &&
(time() - $cached['timestamp']) < ($expiryHours * 3600)) {
self::debugLog("Cache hit: $attr1=$choice1 + $attr2=$choice2");
return [
'success' => true,
'is_impossible' => $cached['is_impossible'],
'reasoning' => $cached['reasoning'],
'cached' => true,
'model_used' => $cached['model'] ?? 'cached',
'daily_cost' => self::$dailyCost
];
}
}
// Make API request for analysis
$prompt = "Analyze this demographic combination for an Indian population:\n\n";
$prompt .= "Combination: $attr1 = '$choice1' AND $attr2 = '$choice2'\n\n";
$prompt .= "Consider:\n";
$prompt .= "- Cultural norms and social structures in India\n";
$prompt .= "- Economic realities and demographics\n";
$prompt .= "- Geographic and social factors\n";
$prompt .= "- Statistical likelihood\n\n";
$prompt .= "Respond with either 'POSSIBLE' or 'IMPOSSIBLE' followed by a brief reason (max 50 words).";
$messages = [
['role' => 'system', 'content' => 'You are a demographic analysis expert specializing in Indian population statistics. Analyze combinations for realism.'],
['role' => 'user', 'content' => $prompt]
];
$response = self::makeRequest($messages, null, 0.1, true);
if ($response['success']) {
$result = trim($response['response']);
$isImpossible = (stripos($result, 'IMPOSSIBLE') === 0) ? 1 : 0;
$reasoning = substr($result, strpos($result, ' ') + 1);
// Cache the result
if (defined('ENABLE_COMBINATION_CACHE') && ENABLE_COMBINATION_CACHE) {
self::$combinationCache[$cacheKey] = [
'is_impossible' => $isImpossible,
'reasoning' => $reasoning,
'timestamp' => time(),
'model' => $response['model_used'] ?? 'unknown'
];
self::saveCache();
self::debugLog("Cached: $attr1=$choice1 + $attr2=$choice2 => " .
($isImpossible ? 'IMPOSSIBLE' : 'POSSIBLE') . " (Future cost savings!)");
}
return [
'success' => true,
'is_impossible' => $isImpossible,
'reasoning' => $reasoning,
'cached' => false,
'model_used' => $response['model_used'] ?? 'unknown',
'daily_cost' => self::$dailyCost
];
}
return [
'success' => false,
'error' => $response['error'],
'is_impossible' => null,
'reasoning' => null
];
}
public static function getCacheStats() {
self::init();
$total = count(self::$combinationCache);
$impossible = 0;
$possible = 0;
foreach (self::$combinationCache as $entry) {
if (isset($entry['is_impossible']) && $entry['is_impossible']) {
$impossible++;
} else {
$possible++;
}
}
// Calculate cost savings from cache using correct constants
$avgInputTokens = defined('AVERAGE_INPUT_TOKENS_PER_REQUEST') ? AVERAGE_INPUT_TOKENS_PER_REQUEST : 150;
$avgOutputTokens = defined('AVERAGE_OUTPUT_TOKENS_PER_REQUEST') ? AVERAGE_OUTPUT_TOKENS_PER_REQUEST : 50;
// Use gpt-4o-mini pricing if available, otherwise fallback
if (defined('GPT4OMINI_COST_PER_1K_INPUT_TOKENS') && defined('GPT4OMINI_COST_PER_1K_OUTPUT_TOKENS')) {
$inputCost = ($avgInputTokens / 1000) * GPT4OMINI_COST_PER_1K_INPUT_TOKENS;
$outputCost = ($avgOutputTokens / 1000) * GPT4OMINI_COST_PER_1K_OUTPUT_TOKENS;
$avgCostPerRequest = $inputCost + $outputCost;
} elseif (defined('GPT35_COST_PER_1K_TOKENS')) {
$avgCostPerRequest = (($avgInputTokens + $avgOutputTokens) / 1000) * GPT35_COST_PER_1K_TOKENS;
} else {
// Fallback to gpt-4o-mini pricing
$avgCostPerRequest = (($avgInputTokens / 1000) * 0.000150) + (($avgOutputTokens / 1000) * 0.000600);
}
$costSavedByCache = $total * $avgCostPerRequest;
return [
'total_cached' => $total,
'impossible_cached' => $impossible,
'possible_cached' => $possible,
'cache_file' => self::$cacheFile,
'cache_size_kb' => file_exists(self::$cacheFile) ? round(filesize(self::$cacheFile) / 1024, 2) : 0,
'rate_limit_hits' => self::$rateLimitHits,
'daily_cost' => self::$dailyCost,
'cost_saved_by_cache' => $costSavedByCache,
'cost_limit' => defined('MAX_DAILY_COST') ? MAX_DAILY_COST : 0
];
}
}
?>
-------------------- END OF FILE --------------------
### FILE 91: syndia.kreahealthcare.com/includes/IntegrityCheckHandler.php
- Type: PHP
- Size: 29.81 KB
- Path: syndia.kreahealthcare.com/includes
- Name: IntegrityCheckHandler.php
------------------------------------------------------------
db = Database::getInstance();
$this->ensureDirectivesTable();
} catch (Exception $e) {
error_log("Database connection error: " . $e->getMessage());
throw $e;
}
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Ensure the directives table exists
*/
private function ensureDirectivesTable() {
// Check if the panel_directives table exists
$result = $this->db->query("SHOW TABLES LIKE 'panel_directives'");
if ($result->num_rows === 0) {
// Create the table if it doesn't exist
$sql = "CREATE TABLE IF NOT EXISTS panel_directives (
id INT AUTO_INCREMENT PRIMARY KEY,
attribute1_id INT NOT NULL,
attribute2_id INT NOT NULL,
choice1 VARCHAR(255) NOT NULL,
choice2 VARCHAR(255) NOT NULL,
attribute1_name VARCHAR(255) NOT NULL,
attribute2_name VARCHAR(255) NOT NULL,
status ENUM('pending', 'approved') NOT NULL DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)";
$this->db->query($sql);
// Add indexes
$this->db->query("ALTER TABLE panel_directives ADD INDEX (attribute1_id)");
$this->db->query("ALTER TABLE panel_directives ADD INDEX (attribute2_id)");
$this->db->query("ALTER TABLE panel_directives ADD INDEX (status)");
// Add foreign key constraints
$this->db->query("ALTER TABLE panel_directives
ADD CONSTRAINT panel_directives_attribute1_fk
FOREIGN KEY (attribute1_id)
REFERENCES attributes(id)
ON DELETE CASCADE");
$this->db->query("ALTER TABLE panel_directives
ADD CONSTRAINT panel_directives_attribute2_fk
FOREIGN KEY (attribute2_id)
REFERENCES attributes(id)
ON DELETE CASCADE");
// Add unique index
$this->db->query("ALTER TABLE panel_directives
ADD UNIQUE INDEX unique_directive (attribute1_id, attribute2_id, choice1(50), choice2(50))");
}
}
/**
* Add a directive to exclude specific attribute combinations
*
* @param string $data JSON data with attribute1_id, attribute2_id, choice1, choice2
* @return array Response with success status and message
*/
public function addDirective($data) {
try {
// Parse the data
$directiveData = json_decode($data, true);
if (!$directiveData) {
throw new Exception("Invalid directive data format");
}
// Validate required fields
if (!isset($directiveData['attribute1_id']) || !isset($directiveData['attribute2_id']) ||
!isset($directiveData['choice1']) || !isset($directiveData['choice2'])) {
throw new Exception("Missing required directive fields");
}
// Get attribute names for better readability
$attribute1Id = (int)$directiveData['attribute1_id'];
$attribute2Id = (int)$directiveData['attribute2_id'];
$choice1 = $this->db->escape($directiveData['choice1']);
$choice2 = $this->db->escape($directiveData['choice2']);
// Get attribute names
$stmt = $this->db->prepare("SELECT id, name FROM attributes WHERE id IN (?, ?)");
$stmt->bind_param('ii', $attribute1Id, $attribute2Id);
$stmt->execute();
$result = $stmt->get_result();
$attributeNames = [];
while ($row = $result->fetch_assoc()) {
$attributeNames[$row['id']] = $row['name'];
}
if (count($attributeNames) !== 2) {
throw new Exception("One or both attributes not found");
}
// Start transaction
$this->db->query("START TRANSACTION");
// Check if this directive already exists
$stmt = $this->db->prepare("
SELECT id FROM panel_directives
WHERE attribute1_id = ? AND attribute2_id = ? AND choice1 = ? AND choice2 = ?
");
$stmt->bind_param('iiss', $attribute1Id, $attribute2Id, $choice1, $choice2);
$stmt->execute();
$existingResult = $stmt->get_result();
if ($existingResult->num_rows > 0) {
throw new Exception("This directive already exists");
}
// Insert the new directive
$stmt = $this->db->prepare("
INSERT INTO panel_directives (
attribute1_id, attribute2_id, choice1, choice2,
attribute1_name, attribute2_name, status, created_at
) VALUES (?, ?, ?, ?, ?, ?, 'pending', NOW())
");
$attr1Name = $attributeNames[$attribute1Id];
$attr2Name = $attributeNames[$attribute2Id];
$stmt->bind_param('iissss',
$attribute1Id, $attribute2Id, $choice1, $choice2,
$attr1Name, $attr2Name
);
if (!$stmt->execute()) {
throw new Exception("Failed to insert directive: " . $stmt->error);
}
$directiveId = $this->db->getLastInsertId();
$this->db->query("COMMIT");
return [
'success' => true,
'directive_id' => $directiveId,
'message' => 'Directive added successfully'
];
} catch (Exception $e) {
if ($this->db->inTransaction()) {
$this->db->query("ROLLBACK");
}
error_log("Error adding directive: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Get all directives
*
* @return array Response with success status and directives data
*/
public function getDirectives() {
try {
$sql = "SELECT id, attribute1_id, attribute2_id, choice1, choice2,
attribute1_name, attribute2_name, status
FROM panel_directives
ORDER BY created_at DESC";
$result = $this->db->query($sql);
if ($result === false) {
throw new Exception("Failed to fetch directives: " . $this->db->getLastError());
}
$directives = [];
while ($row = $result->fetch_assoc()) {
$directives[] = $row;
}
return [
'success' => true,
'directives' => $directives
];
} catch (Exception $e) {
error_log("Error in getDirectives: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Approve a directive
*
* @param int $directiveId The directive ID to approve
* @return array Response with success status and message
*/
public function approveDirective($directiveId) {
try {
$stmt = $this->db->prepare("
UPDATE panel_directives
SET status = 'approved'
WHERE id = ?
");
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to approve directive: " . $stmt->error);
}
if ($stmt->affected_rows === 0) {
throw new Exception("Directive not found");
}
return [
'success' => true,
'message' => 'Directive approved successfully'
];
} catch (Exception $e) {
error_log("Error approving directive: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Revoke an approved directive (set back to pending)
*
* @param int $directiveId The directive ID to revoke
* @return array Response with success status and message
*/
public function revokeDirective($directiveId) {
try {
$stmt = $this->db->prepare("
UPDATE panel_directives
SET status = 'pending'
WHERE id = ?
");
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to revoke directive: " . $stmt->error);
}
if ($stmt->affected_rows === 0) {
throw new Exception("Directive not found");
}
return [
'success' => true,
'message' => 'Directive revoked successfully'
];
} catch (Exception $e) {
error_log("Error revoking directive: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Delete a directive
*
* @param int $directiveId The directive ID to delete
* @return array Response with success status and message
*/
public function deleteDirective($directiveId) {
try {
$stmt = $this->db->prepare("DELETE FROM panel_directives WHERE id = ?");
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to delete directive: " . $stmt->error);
}
if ($stmt->affected_rows === 0) {
throw new Exception("Directive not found");
}
return [
'success' => true,
'message' => 'Directive deleted successfully'
];
} catch (Exception $e) {
error_log("Error deleting directive: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Find panel members that match a specific directive
*
* @param int $directiveId The directive ID to check
* @return array Response with success status and matching panel members
*/
public function findMatchingPanelMembers($directiveId) {
try {
// Get directive details
$stmt = $this->db->prepare("
SELECT attribute1_id, attribute2_id, choice1, choice2
FROM panel_directives
WHERE id = ?
");
$stmt->bind_param('i', $directiveId);
$stmt->execute();
$directive = $stmt->get_result()->fetch_assoc();
if (!$directive) {
throw new Exception("Directive not found");
}
// Find panel members that match this directive
$matchingMembers = [];
// For now, we'll just return success
// In future implementation, we'll add logic to find matching panel members
return [
'success' => true,
'directive_id' => $directiveId,
'matching_count' => count($matchingMembers),
'matching_members' => $matchingMembers
];
} catch (Exception $e) {
error_log("Error finding matching panel members: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Get the current state of the integrity check
*
* @return array|null The current state or null if no state found
*/
public function getCurrentState() {
if ($this->currentState === null) {
$result = $this->db->query("
SELECT * FROM panel_analysis_state
WHERE id = (SELECT MAX(id) FROM panel_analysis_state)
");
if (!$result) {
error_log("Failed to fetch current state: " . $this->db->getLastError());
return null;
}
$this->currentState = $result->fetch_assoc();
}
return $this->currentState;
}
/**
* Update the state of the integrity check
*
* @param array $updates Key-value pairs to update
* @return array Response with success status and message
*/
private function updateState($updates) {
$setClauses = [];
foreach ($updates as $field => $value) {
$setClauses[] = "$field = " .
(is_numeric($value) ? $value : "'" . $this->db->escape($value) . "'");
}
$sql = "UPDATE panel_analysis_state
SET " . implode(', ', $setClauses) . "
WHERE id = (SELECT MAX(id) FROM panel_analysis_state)";
$success = $this->db->query($sql);
if ($success) {
$this->currentState = null;
}
return [
'success' => $success,
'message' => $success ? 'State updated' : 'Failed to update state'
];
}
/**
* Clean up any resources or processes
*
* @return bool Success status
*/
public function cleanup() {
if (!$this->forceCleanup) {
error_log("Skipping automatic cleanup");
return true;
}
$this->db->query("START TRANSACTION");
try {
error_log("Starting forced cleanup process");
$result = $this->db->query("SELECT * FROM panel_analysis_state WHERE is_running = 1");
if ($result && $result->num_rows > 0) {
error_log("Found running processes: " . $result->num_rows);
}
$this->db->query("UPDATE panel_analysis_state SET is_running = 0, status = 'Check terminated' WHERE is_running = 1");
$this->db->query("DELETE FROM panel_processing_status WHERE status IN ('pending', 'processing')");
$lockFile = sys_get_temp_dir() . '/integrity_check.lock';
if (file_exists($lockFile)) {
error_log("Removing lock file");
unlink($lockFile);
}
$this->db->query("COMMIT");
error_log("Cleanup completed successfully");
return true;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Cleanup error: " . $e->getMessage());
throw $e;
}
}
/**
* Force cleanup of resources and processes
*
* @return bool Success status
*/
public function forceCleanup() {
$this->forceCleanup = true;
$result = $this->cleanup();
$this->forceCleanup = false;
return $result;
}
/**
* Start the integrity check process
*/
public function startIntegrityCheck() {
try {
// Create a database table for tracking progress if it doesn't exist
$this->createIntegrityCheckTable();
// Get approved directives
$directives = $this->getApprovedDirectives();
if (empty($directives)) {
throw new Exception("No approved directives found. Please approve directives first.");
}
// Count total panel members
$countResult = $this->db->query("SELECT COUNT(*) as total FROM panel_data");
$totalCount = $countResult->fetch_assoc()['total'];
if ($totalCount == 0) {
throw new Exception("No panel members found to check.");
}
// Reset progress tracking
$this->db->query("TRUNCATE TABLE panel_integrity_check_state");
// Initialize progress state
$sql = "INSERT INTO panel_integrity_check_state
(is_running, is_paused, processed_count, total_count, status, start_time)
VALUES (1, 0, 0, ?, 'running', NOW())";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $totalCount);
if (!$stmt->execute()) {
throw new Exception("Failed to initialize check state: " . $stmt->error);
}
// Create a table to store results if it doesn't exist
$this->createResultsTable();
// Clear previous results
$this->db->query("TRUNCATE TABLE panel_integrity_results");
return [
'success' => true,
'message' => 'Integrity check started successfully'
];
} catch (Exception $e) {
error_log("Start integrity check error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Create the integrity check state table if it doesn't exist
*/
private function createIntegrityCheckTable() {
$this->db->query("
CREATE TABLE IF NOT EXISTS panel_integrity_check_state (
id INT AUTO_INCREMENT PRIMARY KEY,
is_running TINYINT(1) NOT NULL DEFAULT 0,
is_paused TINYINT(1) NOT NULL DEFAULT 0,
processed_count INT NOT NULL DEFAULT 0,
total_count INT NOT NULL DEFAULT 0,
status VARCHAR(50) NOT NULL DEFAULT '',
start_time TIMESTAMP NULL,
last_processed_id INT DEFAULT NULL
)
");
}
/**
* Create the results table if it doesn't exist
*/
private function createResultsTable() {
$this->db->query("
CREATE TABLE IF NOT EXISTS panel_integrity_results (
id INT AUTO_INCREMENT PRIMARY KEY,
panelist_id VARCHAR(10) NOT NULL,
directive_id INT NOT NULL,
attribute1_id INT NOT NULL,
attribute2_id INT NOT NULL,
choice1 VARCHAR(255) NOT NULL,
choice2 VARCHAR(255) NOT NULL,
actual_value1 VARCHAR(255) NOT NULL,
actual_value2 VARCHAR(255) NOT NULL,
attribute1_name VARCHAR(255) NOT NULL,
attribute2_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (panelist_id),
INDEX (directive_id)
)
");
}
/**
* Get approved directives
*/
private function getApprovedDirectives() {
$result = $this->db->query("
SELECT * FROM panel_directives WHERE status = 'approved'
");
$directives = [];
while ($row = $result->fetch_assoc()) {
$directives[] = $row;
}
return $directives;
}
/**
* Pause the integrity check
*/
public function pauseCheck() {
try {
$this->db->query("
UPDATE panel_integrity_check_state
SET is_paused = 1, status = 'paused'
WHERE is_running = 1
");
return [
'success' => true,
'message' => 'Check paused successfully'
];
} catch (Exception $e) {
error_log("Pause check error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Resume the integrity check
*/
public function resumeCheck() {
try {
$this->db->query("
UPDATE panel_integrity_check_state
SET is_paused = 0, status = 'running'
WHERE is_running = 1 AND is_paused = 1
");
return [
'success' => true,
'message' => 'Check resumed successfully'
];
} catch (Exception $e) {
error_log("Resume check error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Stop the integrity check
*/
public function stopCheck() {
try {
$this->db->query("
UPDATE panel_integrity_check_state
SET is_running = 0, is_paused = 0, status = 'stopped'
WHERE is_running = 1
");
return [
'success' => true,
'message' => 'Check stopped successfully'
];
} catch (Exception $e) {
error_log("Stop check error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Get the current check status
*/
public function getCheckStatus() {
try {
$result = $this->db->query("
SELECT * FROM panel_integrity_check_state
ORDER BY id DESC LIMIT 1
");
if ($result->num_rows == 0) {
return [
'success' => true,
'is_running' => false,
'is_paused' => false,
'progress' => 0
];
}
$state = $result->fetch_assoc();
$progress = ($state['total_count'] > 0) ?
($state['processed_count'] / $state['total_count'] * 100) : 0;
return [
'success' => true,
'is_running' => (bool)$state['is_running'],
'is_paused' => (bool)$state['is_paused'],
'progress' => $progress,
'processed' => $state['processed_count'],
'total' => $state['total_count'],
'status' => $state['status']
];
} catch (Exception $e) {
error_log("Get check status error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Get the check progress and process more panel members
*/
public function getCheckProgress() {
try {
// First, get current state
$state = $this->getCheckStatus();
// If check is not running or is paused, just return the state
if (!$state['success'] || !$state['is_running'] || $state['is_paused']) {
return $state;
}
// Process a batch of panel members
$this->processNextBatch();
// Get updated state
$updatedState = $this->getCheckStatus();
// If check is complete, include results
if ($updatedState['success'] &&
(!$updatedState['is_running'] ||
$updatedState['processed'] >= $updatedState['total'])) {
$updatedState['status'] = 'completed';
$updatedState['results'] = $this->getCheckResults();
// Mark as completed
$this->db->query("
UPDATE panel_integrity_check_state
SET is_running = 0, status = 'completed'
WHERE is_running = 1
");
}
return $updatedState;
} catch (Exception $e) {
error_log("Get check progress error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Process the next batch of panel members
*/
private function processNextBatch($batchSize = 50) {
// Get current state
$result = $this->db->query("
SELECT * FROM panel_integrity_check_state
WHERE is_running = 1 AND is_paused = 0
ORDER BY id DESC LIMIT 1
");
if ($result->num_rows == 0) {
return; // No running check
}
$state = $result->fetch_assoc();
$lastProcessedId = $state['last_processed_id'] ?? 0;
// Get approved directives
$directives = $this->getApprovedDirectives();
if (empty($directives)) {
return; // No directives to check
}
// Get a batch of unprocessed panel members
$query = "
SELECT * FROM panel_data
WHERE id > ?
ORDER BY id ASC
LIMIT ?
";
$stmt = $this->db->prepare($query);
$stmt->bind_param('ii', $lastProcessedId, $batchSize);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows == 0) {
// No more panel members to process
$this->db->query("
UPDATE panel_integrity_check_state
SET is_running = 0, status = 'completed',
processed_count = total_count
WHERE id = {$state['id']}
");
return;
}
$processedCount = 0;
$newLastId = $lastProcessedId;
// Check each panel member against directives
while ($panelist = $result->fetch_assoc()) {
$newLastId = $panelist['id'];
$processedCount++;
// Parse attribute values
$attributeValues = json_decode($panelist['attribute_values'], true);
if (!$attributeValues) continue;
// Check against each directive
foreach ($directives as $directive) {
$attr1Id = $directive['attribute1_id'];
$attr2Id = $directive['attribute2_id'];
$choice1 = $directive['choice1'];
$choice2 = $directive['choice2'];
// Get actual values
$actualValue1 = isset($attributeValues[$attr1Id]) ? $attributeValues[$attr1Id] : null;
$actualValue2 = isset($attributeValues[$attr2Id]) ? $attributeValues[$attr2Id] : null;
// Convert arrays to strings for comparison
if (is_array($actualValue1)) $actualValue1 = implode(', ', $actualValue1);
if (is_array($actualValue2)) $actualValue2 = implode(', ', $actualValue2);
// Check if value matches exactly or contains the choice (for array values)
$value1Matches = false;
$value2Matches = false;
// For the first attribute value
if ($actualValue1 === $choice1) {
$value1Matches = true;
} else if (is_string($actualValue1) && strpos($actualValue1, $choice1) !== false) {
// Check if it's part of a comma-separated list (from a multi-select)
$parts = array_map('trim', explode(',', $actualValue1));
if (in_array($choice1, $parts)) {
$value1Matches = true;
}
}
// For the second attribute value
if ($actualValue2 === $choice2) {
$value2Matches = true;
} else if (is_string($actualValue2) && strpos($actualValue2, $choice2) !== false) {
// Check if it's part of a comma-separated list (from a multi-select)
$parts = array_map('trim', explode(',', $actualValue2));
if (in_array($choice2, $parts)) {
$value2Matches = true;
}
}
// Check if panelist violates directive
if ($value1Matches && $value2Matches) {
// This panelist violates the directive - add to results
$stmt = $this->db->prepare("
INSERT INTO panel_integrity_results
(panelist_id, directive_id, attribute1_id, attribute2_id,
choice1, choice2, actual_value1, actual_value2,
attribute1_name, attribute2_name)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->bind_param(
'siisssssss',
$panelist['panelist_id'],
$directive['id'],
$attr1Id,
$attr2Id,
$choice1,
$choice2,
$actualValue1,
$actualValue2,
$directive['attribute1_name'],
$directive['attribute2_name']
);
$stmt->execute();
// Continue checking other directives - a panelist might violate multiple directives
// (removed the break statement here)
}
}
}
// Update progress
$this->db->query("
UPDATE panel_integrity_check_state
SET processed_count = processed_count + {$processedCount},
last_processed_id = {$newLastId}
WHERE id = {$state['id']}
");
}
/**
* Get the results of the integrity check
*/
private function getCheckResults() {
$result = $this->db->query("
SELECT * FROM panel_integrity_results
ORDER BY id ASC
");
$results = [];
while ($row = $result->fetch_assoc()) {
$results[] = $row;
}
return $results;
}
/**
* Delete violating panel members
*/
public function deleteViolatingMembers($panelists) {
try {
if (empty($panelists)) {
throw new Exception("No panelists specified for deletion");
}
$placeholders = implode(',', array_fill(0, count($panelists), '?'));
$types = str_repeat('s', count($panelists));
$stmt = $this->db->prepare("
DELETE FROM panel_data
WHERE panelist_id IN ({$placeholders})
");
$stmt->bind_param($types, ...$panelists);
$stmt->execute();
$deletedCount = $stmt->affected_rows;
return [
'success' => true,
'deleted_count' => $deletedCount,
'message' => "{$deletedCount} panel members deleted successfully"
];
} catch (Exception $e) {
error_log("Delete violating members error: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
}
?>
-------------------- END OF FILE --------------------
### FILE 92: syndia.kreahealthcare.com/includes/IntegrityCheckHandlerBackup.php
- Type: PHP
- Size: 45.64 KB
- Path: syndia.kreahealthcare.com/includes
- Name: IntegrityCheckHandlerBackup.php
------------------------------------------------------------
db = Database::getInstance();
$this->ensureAnomalyTable();
} catch (Exception $e) {
error_log("Database connection error: " . $e->getMessage());
throw $e;
}
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Ensure the anomaly storage table exists
*/
private function ensureAnomalyTable() {
$sql = "CREATE TABLE IF NOT EXISTS panel_anomalies (
id INT AUTO_INCREMENT PRIMARY KEY,
panelist_id VARCHAR(10) NOT NULL,
description TEXT NOT NULL,
attributes_involved VARCHAR(255) NULL,
affected_ids TEXT NULL,
is_processed TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (panelist_id),
INDEX (is_processed)
)";
$this->db->query($sql);
}
public function cleanup() {
if (!$this->forceCleanup) {
error_log("Skipping automatic cleanup");
return true;
}
$this->db->query("START TRANSACTION");
try {
error_log("Starting forced cleanup process");
$result = $this->db->query("SELECT * FROM panel_analysis_state WHERE is_running = 1");
if ($result && $result->num_rows > 0) {
error_log("Found running processes: " . $result->num_rows);
}
$this->db->query("UPDATE panel_analysis_state SET is_running = 0, status = 'Check terminated' WHERE is_running = 1");
$this->db->query("DELETE FROM panel_processing_status WHERE status IN ('pending', 'processing')");
$lockFile = sys_get_temp_dir() . '/integrity_check.lock';
if (file_exists($lockFile)) {
error_log("Removing lock file");
unlink($lockFile);
}
$this->db->query("COMMIT");
error_log("Cleanup completed successfully");
return true;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Cleanup error: " . $e->getMessage());
throw $e;
}
}
public function forceCleanup() {
$this->forceCleanup = true;
$result = $this->cleanup();
$this->forceCleanup = false;
return $result;
}
public function startCheck() {
try {
error_log("Starting integrity check");
// Reset any existing checks
$this->db->query("UPDATE panel_analysis_state SET is_running = 0 WHERE is_running = 1");
$this->db->query("DELETE FROM panel_processing_status WHERE status IN ('pending', 'processing')");
$this->db->query("DELETE FROM panel_anomalies"); // Clear previous anomalies
// Get records that haven't been processed yet, up to $maxRecords
$result = $this->db->query("
SELECT pd.*
FROM panel_data pd
LEFT JOIN panel_processing_status pps ON pd.panelist_id = pps.panelist_id
WHERE pps.panelist_id IS NULL
ORDER BY pd.id
LIMIT {$this->maxRecords}
");
if (!$result) {
error_log("Query error: " . $this->db->getLastError());
throw new Exception("Failed to fetch records: " . $this->db->getLastError());
}
$records = [];
while ($row = $result->fetch_assoc()) {
$records[] = $row;
}
$totalCount = count($records);
error_log("Found $totalCount records to process");
if ($totalCount === 0) {
throw new Exception('No records to process');
}
$this->db->query("START TRANSACTION");
try {
error_log("Initializing new check process");
$stmt = $this->db->prepare("
INSERT INTO panel_analysis_state
(is_running, is_paused, processed_count, total_count, status, start_time)
VALUES (1, 0, 0, ?, 'Starting phase 1: Anomaly detection', NOW())
");
$stmt->bind_param('i', $totalCount);
if (!$stmt->execute()) {
throw new Exception("Failed to initialize integrity check");
}
$stmt = $this->db->prepare("
INSERT INTO panel_processing_status
(panelist_id, status, attempts, last_attempt)
VALUES (?, 'pending', 0, NULL)
");
foreach ($records as $record) {
$stmt->bind_param('s', $record['panelist_id']);
if (!$stmt->execute()) {
error_log("Failed to initialize status for panelist: " . $record['panelist_id']);
throw new Exception("Failed to initialize record status");
}
}
$this->db->query("COMMIT");
error_log("Check process initialized successfully");
return [
'success' => true,
'total_count' => $totalCount,
'message' => 'Integrity check started'
];
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Failed to initialize check: " . $e->getMessage());
throw $e;
}
} catch (Exception $e) {
error_log("Error starting integrity check: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function killExistingProcesses() {
try {
error_log("Killing existing processes");
// Force cleanup any existing processes
$this->db->query("START TRANSACTION");
// Reset all running states
$this->db->query("UPDATE panel_analysis_state SET is_running = 0, status = 'Process terminated' WHERE is_running = 1");
// Clear all pending processes
$this->db->query("DELETE FROM panel_processing_status WHERE status IN ('pending', 'processing')");
// Remove any lock files
$lockFile = sys_get_temp_dir() . '/integrity_check.lock';
if (file_exists($lockFile)) {
unlink($lockFile);
}
// Reset GPT rate limit tracking
if (method_exists('GptHelper', 'resetRateLimit')) {
GptHelper::resetRateLimit();
}
$this->db->query("COMMIT");
error_log("All existing processes killed");
return true;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Error killing processes: " . $e->getMessage());
throw $e;
}
}
/**
* Check if phase 1 is complete and all records have been processed
*/
private function isPhase1Complete() {
$result = $this->db->query("
SELECT COUNT(*) as count
FROM panel_processing_status
WHERE status = 'pending'
");
if (!$result) {
return false;
}
$row = $result->fetch_assoc();
return $row['count'] == 0;
}
/**
* Start phase 2 - grouping anomalies into directives
*/
private function startPhase2() {
$this->db->query("START TRANSACTION");
try {
// Update the state to indicate we're starting phase 2
$stmt = $this->db->prepare("
UPDATE panel_analysis_state
SET status = 'Starting phase 2: Grouping anomalies',
last_processed = NOW()
WHERE is_running = 1
AND id = (SELECT MAX(id) FROM panel_analysis_state)
");
if (!$stmt->execute()) {
throw new Exception("Failed to update state for phase 2");
}
$this->db->query("COMMIT");
$this->currentState = null; // Reset state
// Count anomalies to process
$result = $this->db->query("SELECT COUNT(*) as count FROM panel_anomalies WHERE is_processed = 0");
$anomalyCount = $result->fetch_assoc()['count'];
error_log("Starting phase 2 with $anomalyCount anomalies to process");
return true;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Failed to start phase 2: " . $e->getMessage());
return false;
}
}
/**
* Process a batch of anomalies and create/update directives
*/
public function processAnomalieBatch() {
try {
error_log("Processing anomaly batch");
// Set a processing timeout
set_time_limit(60); // 60 seconds should be plenty for a batch
// Check if we have any unprocessed anomalies
$countQuery = $this->db->query("
SELECT COUNT(*) as count FROM panel_anomalies WHERE is_processed = 0
");
if (!$countQuery) {
throw new Exception("Failed to check anomaly count: " . $this->db->getLastError());
}
$count = $countQuery->fetch_assoc()['count'];
if ($count === 0) {
error_log("No unprocessed anomalies found");
return [
'success' => true,
'status' => 'completed',
'message' => 'All anomalies processed'
];
}
// Group similar anomalies
$processed = $this->groupSimilarAnomalies();
if ($processed > 0) {
error_log("Processed $processed anomalies");
// Check if there are more to process
$remainingQuery = $this->db->query("
SELECT COUNT(*) as count FROM panel_anomalies WHERE is_processed = 0
");
$remaining = $remainingQuery->fetch_assoc()['count'];
if ($remaining > 0) {
return [
'success' => true,
'status' => 'processing',
'processed' => $processed,
'remaining' => $remaining,
'message' => "Processed $processed anomalies, $remaining remaining"
];
} else {
return [
'success' => true,
'status' => 'completed',
'message' => 'All anomalies processed'
];
}
} else {
return [
'success' => true,
'status' => 'completed',
'message' => 'No anomalies to process'
];
}
} catch (Exception $e) {
error_log("Error processing anomalies: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Group similar anomalies into consolidated directives
* This should be called during Phase 2 processing
*/
private function groupSimilarAnomalies() {
try {
// Mark all anomalies as processed
$result = $this->db->query("UPDATE panel_anomalies SET is_processed = 1 WHERE is_processed = 0");
return 1;
} catch (Exception $e) {
error_log("Error in groupSimilarAnomalies: " . $e->getMessage());
return 0;
}
}
private function createDirectiveFromAnomalySimple($anomaly) {
// Insert new directive with minimal data
$stmt = $this->db->prepare("
INSERT INTO panel_directives (
description, record_count, status, created_at
) VALUES (?, 1, 'pending', NOW())
");
$stmt->bind_param('s', $anomaly['description']);
$stmt->execute();
$newId = $this->db->getLastInsertId();
error_log("Created new directive #$newId from anomaly");
}
private function addAnomalyToDirectiveSimple($anomaly, $directiveId) {
try {
// Simply increment the record count
$stmt = $this->db->prepare("
UPDATE panel_directives
SET record_count = record_count + 1
WHERE id = ?
");
if (!$stmt) {
error_log("Failed to prepare statement: " . $this->db->getLastError());
return false;
}
$stmt->bind_param('i', $directiveId);
$result = $stmt->execute();
if (!$result) {
error_log("Failed to update directive: " . $stmt->error);
return false;
}
error_log("Added anomaly to directive $directiveId");
return true;
} catch (Exception $e) {
error_log("Exception adding anomaly to directive: " . $e->getMessage());
return false;
}
}
/**
* Calculate text similarity between two descriptions
*/
private function calculateTextSimilarity($text1, $text2) {
// Convert text to lowercase and remove punctuation
$text1 = strtolower(preg_replace('/[^\w\s]/', '', $text1));
$text2 = strtolower(preg_replace('/[^\w\s]/', '', $text2));
// Extract key concepts that we want to match on
$concepts = [
'age' => ['age', 'years', 'child', 'children', 'minor', 'infant', 'baby', 'toddler', 'young', 'old'],
'income' => ['income', 'rich', 'poor', 'destitute', 'middle', 'class', 'inr', 'salary', 'wage', 'money', 'earn'],
'employment' => ['employment', 'job', 'work', 'employed', 'self-employed', 'labourer', 'labor', 'profession', 'career', 'occupation', 'salaried', 'wages', 'casual'],
'education' => ['education', 'literate', 'illiterate', 'school', 'read', 'write', 'literacy', 'educated']
];
// Calculate concept matches
$conceptMatch = 0;
$conceptTotal = count($concepts);
foreach ($concepts as $category => $terms) {
$match1 = false;
$match2 = false;
foreach ($terms as $term) {
if (strpos($text1, $term) !== false) $match1 = true;
if (strpos($text2, $term) !== false) $match2 = true;
}
// If both texts mention the same concept category, increase similarity
if ($match1 && $match2) {
$conceptMatch++;
}
}
// Calculate basic word similarity (Jaccard)
$stopWords = ['a', 'an', 'the', 'and', 'or', 'but', 'is', 'are', 'in', 'to', 'of', 'for', 'with', 'this', 'that', 'would', 'could', 'might', 'may', 'can'];
$words1 = array_diff(explode(' ', $text1), $stopWords);
$words2 = array_diff(explode(' ', $text2), $stopWords);
$intersection = array_intersect($words1, $words2);
$union = array_unique(array_merge($words1, $words2));
$wordSimilarity = empty($union) ? 0 : count($intersection) / count($union);
// Combine concept matching and word similarity
// Weight concept matching higher since it's more important
$similarity = ($conceptMatch / $conceptTotal) * 0.7 + $wordSimilarity * 0.3;
return $similarity;
}
/**
* Add an anomaly to an existing directive
*/
private function addAnomalyToDirectiveSimple($anomaly, $directiveId) {
try {
// Simply increment the record count
$stmt = $this->db->prepare("
UPDATE panel_directives
SET record_count = record_count + 1
WHERE id = ?
");
if (!$stmt) {
error_log("Failed to prepare statement: " . $this->db->getLastError());
return false;
}
$stmt->bind_param('i', $directiveId);
$result = $stmt->execute();
if (!$result) {
error_log("Failed to update directive: " . $stmt->error);
return false;
}
error_log("Added anomaly to directive $directiveId");
return true;
} catch (Exception $e) {
error_log("Exception adding anomaly to directive: " . $e->getMessage());
return false;
}
}
/**
* Create a new directive from an anomaly
*/
private function createDirectiveFromAnomalySimple($anomaly) {
try {
// Insert new directive with minimal data
$stmt = $this->db->prepare("
INSERT INTO panel_directives (
description, record_count, status, created_at
) VALUES (?, 1, 'pending', NOW())
");
if (!$stmt) {
error_log("Failed to prepare statement: " . $this->db->getLastError());
return false;
}
$stmt->bind_param('s', $anomaly['description']);
$result = $stmt->execute();
if (!$result) {
error_log("Failed to create directive: " . $stmt->error);
return false;
}
$newId = $this->db->getLastInsertId();
error_log("Created new directive #$newId from anomaly");
return true;
} catch (Exception $e) {
error_log("Exception creating directive: " . $e->getMessage());
return false;
}
}
public function processBatch() {
try {
$state = $this->getCurrentState();
error_log("Processing batch, current state: " . json_encode($state));
if (!$state || $state['is_running'] != '1') {
error_log("No active check or check not running");
return ['success' => true, 'status' => 'stopped'];
}
// Check if check is paused
if ($state['is_paused'] == '1') {
error_log("Check is paused");
return [
'success' => true,
'status' => 'paused',
'message' => 'Check is paused'
];
}
// Check if we're in phase 1 or phase 2
if (strpos($state['status'], 'Phase 2') !== false || strpos($state['status'], 'Starting phase 2') !== false) {
// In Phase 2, process anomalies in batches
return $this->processAnomalieBatch();
}
// Check rate limit before processing
if (!GptHelper::canMakeRequest()) {
error_log("Rate limit active, cooling down");
return $this->handleRateLimit(
$state['processed_count'] ?? 0,
$state['total_count'] ?? 0
);
}
// Check if phase 1 is complete
if ($this->isPhase1Complete()) {
// Start phase 2
$this->startPhase2();
// Return immediately to let the next call handle phase 2
return [
'success' => true,
'status' => 'switching_phase',
'message' => 'Starting phase 2: Grouping anomalies'
];
}
// Phase 1: Get next batch of pending records
$stmt = $this->db->prepare("
SELECT pd.*
FROM panel_processing_status pps
JOIN panel_data pd ON pps.panelist_id = pd.panelist_id
WHERE pps.status = 'pending'
ORDER BY pps.panelist_id
LIMIT ?
");
$stmt->bind_param('i', $this->batchSize);
$stmt->execute();
$result = $stmt->get_result();
if (!$result) {
throw new Exception("Failed to fetch pending records");
}
$records = [];
while ($row = $result->fetch_assoc()) {
$records[] = $row;
}
if (empty($records)) {
// No more pending records - check if we're done
$remainingResult = $this->db->query("
SELECT COUNT(*) as count
FROM panel_processing_status
WHERE status = 'pending'
");
$remaining = $remainingResult->fetch_assoc()['count'];
if ($remaining == 0) {
// Start phase 2
$this->startPhase2();
return [
'success' => true,
'status' => 'switching_phase',
'message' => 'Starting phase 2: Grouping anomalies'
];
}
return [
'success' => true,
'status' => 'waiting',
'message' => 'Waiting for more records'
];
}
// Process this batch of records
$processed = 0;
$successful = $state['processed_count'] ?? 0;
// Get attributes only once for the batch
$attributes = $this->getAttributeMetadata();
foreach ($records as $record) {
try {
// Mark record as processing
$this->markRecordStatus($record['panelist_id'], 'processing');
// Check if we can make a request
if (!GptHelper::canMakeRequest()) {
// Return immediately to avoid wasting time
return $this->handleRateLimit(
$successful,
$state['total_count'] ?? 0,
$record['panelist_id']
);
}
// Check record for logical inconsistencies
$inconsistencies = $this->checkRecordIntegrity($record, $attributes);
// Save any inconsistencies found
foreach ($inconsistencies as $description) {
error_log("Found inconsistency for {$record['panelist_id']}: $description");
$this->saveAnomaly($record['panelist_id'], $description);
}
// Mark as completed regardless of whether inconsistencies were found
$this->markRecordStatus($record['panelist_id'], 'completed');
$successful++;
$processed++;
} catch (Exception $e) {
error_log("Error processing record: " . $e->getMessage());
$this->markRecordStatus($record['panelist_id'], 'failed');
$processed++;
// Check if this is a rate limit error
if (stripos($e->getMessage(), 'rate limit') !== false) {
return $this->handleRateLimit(
$successful,
$state['total_count'] ?? 0,
$record['panelist_id']
);
}
}
}
// Update state with progress
$totalPanel = $state['total_count'] ?? 0;
$progress = round(($successful / $totalPanel) * 100, 2);
$this->updateState([
'processed_count' => $successful,
'status' => "Phase 1: Processed $successful of $totalPanel records ($progress%)",
'last_processed' => date('Y-m-d H:i:s')
]);
return [
'success' => true,
'status' => 'processing',
'progress' => $progress,
'processed' => $successful,
'total' => $totalPanel
];
} catch (Exception $e) {
error_log("Batch processing error: " . $e->getMessage());
return ['success' => false, 'message' => $e->getMessage()];
}
}
private function handleRateLimit($successful, $totalPanel, $panelistId = null) {
if ($panelistId) {
$this->markRecordStatus($panelistId, 'pending');
}
$progress = round(($successful / $totalPanel) * 100, 2);
$this->updateState([
'is_running' => '1', // Keep process running
'processed_count' => $successful,
'status' => "Rate limit cooling down... Progress: $progress% (Successful: $successful)",
'last_processed' => date('Y-m-d H:i:s')
]);
return [
'success' => true,
'status' => 'cooling',
'message' => 'Rate limit cooling down',
'progress' => $progress
];
}
/**
* Check a record for logical inconsistencies
* Returns array of inconsistency descriptions
*/
public function checkRecordIntegrity($record, $attributes) {
$maxRetries = GPT_MAX_RETRIES;
$attempt = 0;
do {
try {
if ($attempt > 0) {
error_log("Retrying integrity check for record {$record['panelist_id']}, attempt $attempt");
sleep(GPT_RETRY_DELAY);
}
$attributeValues = json_decode($record['attribute_values'], true);
if (!$attributeValues) {
throw new Exception("Invalid attribute values format");
}
$profileData = [];
foreach ($attributeValues as $attrId => $value) {
if (isset($attributes[$attrId])) {
$profileData[$attributes[$attrId]['name']] = $value;
}
}
if (empty($profileData)) {
throw new Exception("No valid attributes found");
}
if (!GptHelper::canMakeRequest()) {
sleep(GPT_COOLDOWN_PERIOD);
continue;
}
$messages = [
[
'role' => 'system',
'content' => 'You are an expert demographic analyst focused on identifying logical inconsistencies in demographic profiles. You are analyzing synthetic panel data to find combinations of demographic attributes that would not be plausible in the real world.'
],
[
'role' => 'user',
'content' => $this->prepareGptPrompt($profileData)
]
];
$response = GptHelper::makeRequest($messages);
if (empty($response)) {
throw new Exception("Empty response from GPT");
}
$inconsistencies = $this->parseGptResponse($response);
return $inconsistencies;
} catch (Exception $e) {
error_log("GPT request failed: " . $e->getMessage());
if (stripos($e->getMessage(), 'rate limit') !== false) {
$attempt++;
if ($attempt >= $maxRetries) {
error_log("Final failure checking record {$record['panelist_id']}: " . $e->getMessage());
return [];
}
sleep(GPT_COOLDOWN_PERIOD);
continue;
}
throw $e;
}
} while ($attempt < $maxRetries);
return [];
}
private function prepareGptPrompt($profileData) {
$prompt = "Analyze this demographic profile for logical inconsistencies or impossible combinations of attributes:\n\n";
foreach ($profileData as $attribute => $value) {
$prompt .= "$attribute: $value\n";
}
$prompt .= "\nIdentify any combinations of attributes that would be logically inconsistent or impossible in the real world. ";
$prompt .= "For example, children under 5 years old cannot have jobs, a person cannot be both married and single simultaneously, etc.\n\n";
$prompt .= "Format your response as follows:\n";
$prompt .= "1. If you find ANY logical inconsistencies, start each one with 'INCONSISTENCY:' followed by a clear explanation.\n";
$prompt .= "2. If the profile is logically consistent, respond with 'CONSISTENT: No logical inconsistencies found.'\n\n";
$prompt .= "Be thorough and check for all possible inconsistencies between age, education, employment, marital status, etc. Focus only on logical impossibilities, not statistical unlikelihood.";
return $prompt;
}
private function parseGptResponse($response) {
error_log("Parsing GPT response: " . $response);
$inconsistencies = [];
$lines = explode("\n", $response);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) continue;
// Skip if explicitly marked as consistent
if (stripos($line, 'CONSISTENT:') === 0) {
error_log("Profile marked as consistent");
continue;
}
// Extract inconsistency descriptions
if (preg_match('/^INCONSISTENCY:\s*(.+)$/i', $line, $matches)) {
$description = $this->standardizeDescription(trim($matches[1]));
error_log("Found inconsistency: $description");
$inconsistencies[] = $description;
}
}
error_log("Total inconsistencies found: " . count($inconsistencies));
return $inconsistencies;
}
/**
* Save an anomaly for later grouping
*/
private function saveAnomaly($panelistId, $description) {
try {
error_log("Saving anomaly for panelist $panelistId: $description");
// Extract attribute names from the description
$attributePattern = '/\b(Gender|Age|Employment Type|Urbanization|Literacy|Gross Annual Income|Religion|Education|Marital Status)\b/i';
preg_match_all($attributePattern, $description, $matches);
$attributesInvolved = implode(', ', array_unique($matches[0]));
$affectedIds = json_encode([$panelistId]);
$stmt = $this->db->prepare("
INSERT INTO panel_anomalies (panelist_id, description, attributes_involved, affected_ids)
VALUES (?, ?, ?, ?)
");
if (!$stmt) {
error_log("Failed to prepare statement: " . $this->db->getLastError());
return false;
}
$stmt->bind_param('ssss', $panelistId, $description, $attributesInvolved, $affectedIds);
$result = $stmt->execute();
if (!$result) {
error_log("Failed to save anomaly: " . $stmt->error);
return false;
}
error_log("Successfully saved anomaly for $panelistId");
return true;
} catch (Exception $e) {
error_log("Exception saving anomaly: " . $e->getMessage());
return false;
}
}
private function standardizeDescription($description) {
// Remove patterns like "Profile indicates" or "This profile shows"
$description = preg_replace('/^(the\s+)?(profile|record|data)\s+(indicates|shows|has|contains|suggests|presents|features)\s+/i', '', $description);
// Use present tense and declarative form
$description = preg_replace('/^there\s+is\s+an?\s+inconsistency\s+(with|between|in)\s+/i', '', $description);
// Normalize ages
$description = preg_replace('/\ba(?:ge)?\s+of\s+(\d+)\b/i', '$1 years old', $description);
// Normalize general inconsistency phrases
$description = preg_replace('/^(it\s+is|this\s+is)\s+(impossible|not\s+possible|inconsistent)\s+for\s+/i', '', $description);
return trim($description);
}
private function findSimilarDirective($description) {
$sql = "SELECT id, description FROM panel_directives WHERE status != 'resolved'";
$result = $this->db->query($sql);
if (!$result) {
error_log("Failed to query directives: " . $this->db->getLastError());
return null;
}
while ($row = $result->fetch_assoc()) {
similar_text($description, $row['description'], $percent);
if ($percent > 70) { // 70% similarity threshold
return $row;
}
}
return null;
}
private function markRecordStatus($panelistId, $status) {
$sql = "
INSERT INTO panel_processing_status (panelist_id, status, attempts, last_attempt)
VALUES (?, ?, 1, NOW())
ON DUPLICATE KEY UPDATE
status = VALUES(status),
attempts = attempts + 1,
last_attempt = NOW()
";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('ss', $panelistId, $status);
$stmt->execute();
}
public function getAttributeMetadata() {
$result = $this->db->query("SELECT id, name, choices FROM attributes ORDER BY id");
$attributes = [];
while ($row = $result->fetch_assoc()) {
$attributes[$row['id']] = [
'name' => $row['name'],
'choices' => json_decode($row['choices'], true)
];
}
return $attributes;
}
public function getCurrentState() {
if ($this->currentState === null) {
$result = $this->db->query("
SELECT * FROM panel_analysis_state
WHERE id = (SELECT MAX(id) FROM panel_analysis_state)
");
if (!$result) {
error_log("Failed to fetch current state: " . $this->db->getLastError());
return null;
}
$this->currentState = $result->fetch_assoc();
}
return $this->currentState;
}
private function updateState($updates) {
$setClauses = [];
foreach ($updates as $field => $value) {
$setClauses[] = "$field = " .
(is_numeric($value) ? $value : "'" . $this->db->escape($value) . "'");
}
$sql = "UPDATE panel_analysis_state
SET " . implode(', ', $setClauses) . "
WHERE id = (SELECT MAX(id) FROM panel_analysis_state)";
$success = $this->db->query($sql);
if ($success) {
$this->currentState = null;
}
return [
'success' => $success,
'message' => $success ? 'State updated' : 'Failed to update state'
];
}
public function pauseCheck() {
try {
$sql = "UPDATE panel_analysis_state
SET is_paused = 1,
status = 'Check paused'
WHERE is_running = 1
AND id = (SELECT MAX(id) FROM panel_analysis_state)";
$this->db->query($sql);
$this->currentState = null; // Reset current state
return [
'success' => true,
'message' => 'Check paused successfully'
];
} catch (Exception $e) {
error_log("Error pausing check: " . $e->getMessage());
return [
'success' => false,
'message' => 'Failed to pause check: ' . $e->getMessage()
];
}
}
public function resumeCheck() {
try {
$sql = "UPDATE panel_analysis_state
SET is_paused = 0,
status = 'Check resumed'
WHERE is_running = 1
AND is_paused = 1
AND id = (SELECT MAX(id) FROM panel_analysis_state)";
$this->db->query($sql);
$this->currentState = null; // Reset current state
return [
'success' => true,
'message' => 'Check resumed successfully'
];
} catch (Exception $e) {
error_log("Error resuming check: " . $e->getMessage());
return [
'success' => false,
'message' => 'Failed to resume check: ' . $e->getMessage()
];
}
}
public function addDirective($description) {
try {
$description = trim($description);
if (empty($description)) {
throw new Exception("Directive description cannot be empty");
}
// Start transaction
$this->db->query("START TRANSACTION");
// Insert new directive
$stmt = $this->db->prepare("
INSERT INTO panel_directives (description, record_count, status)
VALUES (?, 0, 'pending')
");
$stmt->bind_param('s', $description);
if (!$stmt->execute()) {
throw new Exception("Failed to create directive");
}
$directiveId = $this->db->getLastInsertId();
$this->db->query("COMMIT");
return [
'success' => true,
'directive_id' => $directiveId,
'message' => 'Directive added successfully'
];
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Error creating directive: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function getDirectives() {
try {
error_log("Getting directives - start");
$sql = "SELECT id, description, record_count, status, last_resolved,
DATE_FORMAT(created_at, '%b %d, %Y %H:%i') as created_date
FROM panel_directives
ORDER BY created_at DESC";
$result = $this->db->query($sql);
if ($result === false) {
error_log("Database query failed: " . $this->db->getLastError());
throw new Exception("Failed to fetch directives");
}
$directives = [];
while ($row = $result->fetch_assoc()) {
$directives[] = [
'id' => $row['id'],
'description' => $row['description'],
'record_count' => (int)($row['record_count'] ?? 0),
'status' => $row['status'],
'last_resolved' => $row['last_resolved'],
'created_date' => $row['created_date']
];
}
$response = [
'success' => true,
'directives' => $directives
];
return $response;
} catch (Exception $e) {
error_log("Error in getDirectives: " . $e->getMessage());
error_log("Stack trace: " . $e->getTraceAsString());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function handleDirectiveAction($directiveId, $action) {
try {
error_log("Handling directive action: $action for directive ID: $directiveId");
$this->db->query("START TRANSACTION");
$status = '';
switch($action) {
case 'approve':
$status = 'approved';
break;
case 'reject':
$status = 'rejected';
break;
case 'resolve':
$status = 'resolved';
break;
default:
throw new Exception("Invalid action");
}
error_log("Setting status to: $status");
$sql = "UPDATE panel_directives SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?";
$stmt = $this->db->prepare($sql);
if (!$stmt) {
throw new Exception("Failed to prepare statement: " . $this->db->getLastError());
}
$stmt->bind_param('si', $status, $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to update directive status: " . $stmt->error);
}
error_log("Rows affected: " . $stmt->affected_rows);
$this->db->query("COMMIT");
return [
'success' => true,
'message' => "Directive {$status} successfully"
];
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Error handling directive action: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function checkAffectedMembers($directiveId) {
try {
error_log("Starting checkAffectedMembers for directive: " . $directiveId);
// Get all panel members with this directive
$sql = "SELECT panelist_id FROM directive_records WHERE directive_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $directiveId);
$stmt->execute();
$result = $stmt->get_result();
$affectedMembers = [];
while ($row = $result->fetch_assoc()) {
$affectedMembers[] = $row['panelist_id'];
}
// Get the directive description
$stmt = $this->db->prepare("SELECT description FROM panel_directives WHERE id = ?");
$stmt->bind_param('i', $directiveId);
$stmt->execute();
$result = $stmt->get_result();
$directive = $result->fetch_assoc();
if (!$directive) {
throw new Exception("Directive not found");
}
$count = count($affectedMembers);
error_log("Found {$count} affected members for directive {$directiveId}");
return [
'success' => true,
'affected_count' => $count,
'description' => $directive['description'],
'affected_members' => $affectedMembers
];
} catch (Exception $e) {
error_log("Error in checkAffectedMembers: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function applyResolveAction($directiveId) {
try {
$this->db->query("START TRANSACTION");
// Get affected panelist IDs
$sql = "SELECT DISTINCT panelist_id FROM directive_records WHERE directive_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $directiveId);
$stmt->execute();
$result = $stmt->get_result();
$affected = [];
while ($row = $result->fetch_assoc()) {
$affected[] = $this->db->escape($row['panelist_id']);
}
if (!empty($affected)) {
// Delete affected panel members
$panelist_ids = "'" . implode("','", $affected) . "'";
$delete_sql = "DELETE FROM panel_data WHERE panelist_id IN ($panelist_ids)";
if (!$this->db->query($delete_sql)) {
throw new Exception("Failed to delete affected panel members");
}
}
// Update directive status and last_resolved
$sql = "UPDATE panel_directives
SET status = 'resolved',
last_resolved = CURRENT_TIMESTAMP
WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $directiveId);
if (!$stmt->execute()) {
throw new Exception("Failed to update directive status");
}
$this->db->query("COMMIT");
return [
'success' => true,
'message' => 'Directive resolved successfully',
'affected_count' => count($affected)
];
} catch (Exception $e) {
$this->db->query("ROLLBACK");
error_log("Error in applyResolveAction: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
public function resetStuckProcess() {
try {
$sql = "UPDATE panel_analysis_state
SET is_running = 0,
status = 'Check terminated due to inactivity'
WHERE is_running = 1
AND last_processed < DATE_SUB(NOW(), INTERVAL 5 MINUTE)";
$this->db->query($sql);
return true;
} catch (Exception $e) {
error_log("Error resetting stuck process: " . $e->getMessage());
return false;
}
}
}
-------------------- END OF FILE --------------------
### FILE 93: syndia.kreahealthcare.com/includes/survey_functions.php
- Type: PHP
- Size: 14.75 KB
- Path: syndia.kreahealthcare.com/includes
- Name: survey_functions.php
------------------------------------------------------------
db = Database::getInstance();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Get all surveys for a user with summary statistics
*/
public function getSurveys($userId, $filters = []) {
try {
$where = ['s.created_by = ?'];
$params = [$userId];
$types = 'i';
if (!empty($filters['status'])) {
$where[] = 's.status = ?';
$params[] = $filters['status'];
$types .= 's';
}
if (!empty($filters['search'])) {
$where[] = '(s.title LIKE ? OR s.description LIKE ?)';
$search = "%{$filters['search']}%";
$params[] = $search;
$params[] = $search;
$types .= 'ss';
}
$whereClause = implode(' AND ', $where);
$sql = "SELECT
s.*,
(SELECT COUNT(DISTINCT t.id)
FROM survey_tokens t
WHERE t.survey_id = s.id) as tokens_count,
(SELECT COUNT(DISTINCT t.id)
FROM survey_tokens t
WHERE t.survey_id = s.id AND t.is_completed = 1) as responses_count,
(SELECT COUNT(DISTINCT q.id)
FROM survey_questions q
WHERE q.survey_id = s.id) as questions_count
FROM surveys s
WHERE $whereClause
ORDER BY s.created_at DESC";
$stmt = $this->db->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_all(MYSQLI_ASSOC);
} catch (Exception $e) {
error_log("Get surveys error: " . $e->getMessage());
return [];
}
}
/**
* Get questions for a specific survey
*/
public function getSurveyQuestions($surveyId) {
try {
$sql = "SELECT *
FROM survey_questions
WHERE survey_id = ?
ORDER BY question_order ASC";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$questions = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
// Parse JSON fields for each question
foreach ($questions as &$question) {
if (!empty($question['options'])) {
$question['options'] = json_decode($question['options'], true);
}
if (!empty($question['config'])) {
$question['config'] = json_decode($question['config'], true);
}
}
return $questions;
} catch (Exception $e) {
error_log("Get survey questions error: " . $e->getMessage());
return [];
}
}
/**
* Create a new survey
*/
public function createSurvey($data) {
try {
$sql = "INSERT INTO surveys (
title, description, status,
allow_multiple, allow_edit, created_by
) VALUES (?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('sssiii',
$data['title'],
$data['description'],
$data['status'],
$data['allow_multiple'],
$data['allow_edit'],
$data['created_by']
);
if (!$stmt->execute()) {
throw new Exception("Failed to create survey");
}
return [
'success' => true,
'survey_id' => $this->db->getLastInsertId()
];
} catch (Exception $e) {
error_log("Create survey error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Get survey details with questions
*/
public function getSurveyDetails($surveyId, $userId) {
try {
// Get survey details
$sql = "SELECT * FROM surveys
WHERE id = ? AND created_by = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('ii', $surveyId, $userId);
$stmt->execute();
$survey = $stmt->get_result()->fetch_assoc();
if (!$survey) {
return null;
}
// Get questions
$sql = "SELECT * FROM survey_questions
WHERE survey_id = ?
ORDER BY question_order ASC";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$survey['questions'] = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
// Get response statistics
$sql = "SELECT
COUNT(DISTINCT st.id) as total_tokens,
SUM(st.is_completed) as completed_responses,
COUNT(DISTINCT sr.selection_id) as unique_responses
FROM survey_tokens st
LEFT JOIN survey_responses sr ON sr.survey_id = st.survey_id
WHERE st.survey_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$survey['stats'] = $stmt->get_result()->fetch_assoc();
return $survey;
} catch (Exception $e) {
error_log("Get survey details error: " . $e->getMessage());
return null;
}
}
/**
* Update survey details
*/
public function updateSurvey($surveyId, $data) {
try {
$sql = "UPDATE surveys
SET title = ?,
description = ?,
status = ?,
allow_multiple = ?,
allow_edit = ?
WHERE id = ? AND created_by = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('sssiiii',
$data['title'],
$data['description'],
$data['status'],
$data['allow_multiple'],
$data['allow_edit'],
$surveyId,
$data['created_by']
);
if (!$stmt->execute()) {
throw new Exception("Failed to update survey");
}
return ['success' => true];
} catch (Exception $e) {
error_log("Update survey error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Delete a survey
*/
public function deleteSurvey($surveyId, $userId) {
try {
$sql = "DELETE FROM surveys
WHERE id = ? AND created_by = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('ii', $surveyId, $userId);
if (!$stmt->execute()) {
throw new Exception("Failed to delete survey");
}
return ['success' => true];
} catch (Exception $e) {
error_log("Delete survey error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Add or update survey questions
*/
public function saveQuestion($data) {
try {
if (isset($data['question_id'])) {
// Update existing question
$sql = "UPDATE survey_questions
SET question_text = ?,
question_type = ?,
help_text = ?,
options = ?,
config = ?,
is_required = ?
WHERE id = ? AND survey_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('sssssiis',
$data['question_text'],
$data['question_type'],
$data['help_text'],
$data['options'],
$data['config'],
$data['is_required'],
$data['question_id'],
$data['survey_id']
);
} else {
// Add new question
$sql = "INSERT INTO survey_questions (
survey_id, question_text, question_type,
help_text, options, config, is_required, question_order
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('isssssii',
$data['survey_id'],
$data['question_text'],
$data['question_type'],
$data['help_text'],
$data['options'],
$data['config'],
$data['is_required'],
$data['question_order']
);
}
if (!$stmt->execute()) {
throw new Exception("Failed to save question");
}
return [
'success' => true,
'question_id' => isset($data['question_id']) ?
$data['question_id'] : $this->db->getLastInsertId()
];
} catch (Exception $e) {
error_log("Save question error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Delete a survey question
*/
public function deleteQuestion($questionId, $surveyId) {
try {
$sql = "DELETE FROM survey_questions
WHERE id = ? AND survey_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('ii', $questionId, $surveyId);
if (!$stmt->execute()) {
throw new Exception("Failed to delete question");
}
return ['success' => true];
} catch (Exception $e) {
error_log("Delete question error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Update question order
*/
public function updateQuestionOrder($surveyId, $questionOrder) {
try {
$sql = "UPDATE survey_questions
SET question_order = ?
WHERE id = ? AND survey_id = ?";
$stmt = $this->db->prepare($sql);
foreach ($questionOrder as $order => $questionId) {
$stmt->bind_param('iii', $order, $questionId, $surveyId);
if (!$stmt->execute()) {
throw new Exception("Failed to update question order");
}
}
return ['success' => true];
} catch (Exception $e) {
error_log("Update question order error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Generate survey token for a panel
*/
public function generateSurveyToken($surveyId, $sampleId, $selectionId, $expiryHours = 48) {
try {
$token = bin2hex(random_bytes(32));
$expiryDate = date('Y-m-d H:i:s', strtotime("+{$expiryHours} hours"));
$sql = "INSERT INTO survey_tokens (
survey_id, token, sample_id,
selection_id, expires_at
) VALUES (?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('issis',
$surveyId,
$token,
$sampleId,
$selectionId,
$expiryDate
);
if (!$stmt->execute()) {
throw new Exception("Failed to generate survey token");
}
return [
'success' => true,
'token' => $token
];
} catch (Exception $e) {
error_log("Generate token error: " . $e->getMessage());
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
/**
* Get survey response statistics
*/
public function getSurveyStats($surveyId) {
try {
$sql = "SELECT
COUNT(DISTINCT st.id) as total_tokens,
SUM(st.is_completed) as completed_responses,
COUNT(DISTINCT sr.selection_id) as unique_responses,
AVG(TIMESTAMPDIFF(MINUTE, st.created_at, st.completed_at)) as avg_completion_time
FROM survey_tokens st
LEFT JOIN survey_responses sr ON sr.survey_id = st.survey_id
WHERE st.survey_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$stats = $stmt->get_result()->fetch_assoc();
// Get per-question statistics
$sql = "SELECT
sq.id, sq.question_text, sq.question_type,
COUNT(DISTINCT sr.selection_id) as response_count,
GROUP_CONCAT(DISTINCT sr.response) as responses
FROM survey_questions sq
LEFT JOIN survey_responses sr ON sr.question_id = sq.id
WHERE sq.survey_id = ?
GROUP BY sq.id";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $surveyId);
$stmt->execute();
$stats['questions'] = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
return $stats;
} catch (Exception $e) {
error_log("Get survey stats error: " . $e->getMessage());
return null;
}
}
}
?>
-------------------- END OF FILE --------------------
================================================================================
## SUMMARY
================================================================================
Repository contains 93 files total.
All file contents have been extracted and are shown above.
This repository snapshot was generated on: 2025-10-26 18:59:36
================================================================================
## END OF REPOSITORY
================================================================================