Created
May 9, 2025 07:11
-
-
Save Tayyab20/3d71a24f6e1023758c89b07d11914e27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* POLARIS Mail Handler | |
* | |
* This script handles report generation and email sending based on chat and assessment data. | |
* It directly integrates with localStorage data from chat.php and grading.php. | |
*/ | |
// Set execution time limit to 10 minutes (600 seconds) | |
set_time_limit(600); | |
// Allow the script to run even if the client disconnects | |
ignore_user_abort(true); | |
// Create logs directory if it doesn't exist | |
$logDir = 'logs'; | |
if (!is_dir($logDir)) { | |
mkdir($logDir, 0755, true); | |
} | |
$logFile = $logDir . '/report_generation_' . date('Y-m-d') . '.log'; | |
// Start timing for performance measurement | |
$startTime = microtime(true); | |
// Only set headers if not running from CLI | |
if (php_sapi_name() !== 'cli') { | |
// Set appropriate headers | |
header('Content-Type: application/json; charset=UTF-8'); | |
} | |
// Check for test request data first | |
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty(file_get_contents('php://input')) && file_exists(__DIR__ . '/test_request.json')) { | |
$requestBody = file_get_contents(__DIR__ . '/test_request.json'); | |
logMessage("Using test request data from test_request.json"); | |
} else { | |
$requestBody = file_get_contents('php://input'); | |
} | |
// Include PHPMailer | |
require_once __DIR__ . '/vendor/autoload.php'; | |
require 'db_connection.php'; // Connect to DB | |
use PHPMailer\PHPMailer\PHPMailer; | |
use PHPMailer\PHPMailer\SMTP; | |
use PHPMailer\PHPMailer\Exception; | |
// RuntimeException is already in global namespace, so no need to import it | |
// Function to log messages | |
function logMessage($message) { | |
global $logFile; | |
$logMessage = date('Y-m-d H:i:s') . " | $message\n"; | |
file_put_contents($logFile, $logMessage, FILE_APPEND); | |
error_log("MAIL_HANDLER: " . $message); | |
} | |
// Log start of script execution | |
logMessage("Mail handler script started"); | |
function findUserChatData($userId) { | |
global $pdo; | |
try { | |
$stmt = $pdo->prepare("SELECT chat_data FROM chat_sessions WHERE user_id = ? ORDER BY updated_at DESC LIMIT 1"); | |
$stmt->execute([$userId]); | |
$chatDataJson = $stmt->fetchColumn(); | |
if ($chatDataJson) { | |
$chatData = json_decode($chatDataJson, true); | |
if (is_array($chatData) && !empty($chatData)) { | |
logMessage("Found chat data in database for user ID: {$userId}"); | |
// Check if message limit was hit and the data was summarized | |
if (isset($chatData['chat_summary'])) { | |
logMessage("Found pre-summarized chat data: {$chatData['chat_summary']['original_message_count']} original messages"); | |
} else { | |
logMessage("Found regular (not summarized) chat data"); | |
} | |
return $chatData; | |
} | |
} | |
logMessage("No chat data found in database for user ID: {$userId}"); | |
return null; | |
} catch (Exception $e) { | |
logMessage("Error fetching chat data from database: " . $e->getMessage()); | |
return null; | |
} | |
} | |
function findGradingData($userId) { | |
global $pdo; | |
try { | |
// First try to get grading data from the assessment table | |
$stmt = $pdo->prepare("SELECT assessment_data FROM user_assessments WHERE user_id = ? ORDER BY updated_at DESC LIMIT 1"); | |
$stmt->execute([$userId]); | |
$gradingDataJson = $stmt->fetchColumn(); | |
if ($gradingDataJson) { | |
$gradingData = json_decode($gradingDataJson, true); | |
if (is_array($gradingData) && !empty($gradingData)) { | |
logMessage("Found grading data in database for user ID: {$userId}"); | |
// Debug: Log the grading data structure | |
if (isset($gradingData['answers'])) { | |
logMessage("Found " . count($gradingData['answers']) . " answers in grading data"); | |
} else { | |
logMessage("Warning: No 'answers' key in grading data"); | |
} | |
return $gradingData; | |
} | |
} | |
// If no assessment data found, try to get from chat data as fallback | |
$chatData = findUserChatData($userId); | |
if ($chatData && isset($chatData['answers'])) { | |
logMessage("Using answers from chat data as fallback"); | |
return ['answers' => $chatData['answers']]; | |
} | |
logMessage("No grading data found in database for user ID: {$userId}"); | |
return null; | |
} catch (Exception $e) { | |
logMessage("Error fetching grading data from database: " . $e->getMessage()); | |
return null; | |
} | |
} | |
function extractMessages($chatData) { | |
if (isset($chatData['messages']) && is_array($chatData['messages'])) { | |
logMessage("Extracted " . count($chatData['messages']) . " messages from chat data"); | |
return $chatData['messages']; | |
} | |
logMessage("No messages found in chat data"); | |
return []; | |
} | |
function extractAnswers($chatData) { | |
if (isset($chatData['answers']) && is_array($chatData['answers'])) { | |
logMessage("Extracted " . count($chatData['answers']) . " answers from chat data"); | |
return $chatData['answers']; | |
} | |
logMessage("No answers found in chat data"); | |
return []; | |
} | |
function createDummyConversation($userData) { | |
$userName = $userData['name'] ?? 'Kullanıcı'; | |
logMessage("Creating dummy conversation for user: {$userName}"); | |
// Get current time in milliseconds | |
$now = round(microtime(true) * 1000); | |
// Create a basic conversation with a few messages | |
return [ | |
[ | |
'role' => 'system', | |
'content' => 'Hoş geldiniz! Polaris ile sohbetiniz başlıyor.', | |
'timestamp' => $now - 3600000, // 1 hour ago | |
'username' => $userName | |
], | |
[ | |
'role' => 'assistant', | |
'content' => "Merhaba! Ben Polaris, dijital strateji rehberiniz. Size nasıl yardımcı olabilirim?", | |
'timestamp' => $now - 3500000, | |
'username' => $userName | |
], | |
[ | |
'role' => 'user', | |
'content' => "Merhaba, ben {$userName}", | |
'timestamp' => $now - 3400000, | |
'username' => $userName | |
], | |
[ | |
'role' => 'assistant', | |
'content' => "Merhaba {$userName}! Bugün dijital stratejileriniz hakkında konuşalım. İşinizde hangi teknolojileri kullanıyorsunuz?", | |
'timestamp' => $now - 3300000, | |
'username' => $userName | |
], | |
[ | |
'role' => 'user', | |
'content' => "Genellikle ofis uygulamaları ve şirketimizin özel sistemlerini kullanıyorum.", | |
'timestamp' => $now - 3200000, | |
'username' => $userName | |
] | |
]; | |
} | |
function generateConversationSummary($messages, $userData, $metrics = [], $chatData = null) { | |
logMessage("Generating conversation summary"); | |
// Check if we have a pre-summarized chat data with user messages text | |
if ($chatData && isset($chatData['chat_summary']) && isset($chatData['chat_summary']['user_messages_text'])) { | |
logMessage("Using pre-summarized user messages text from chat.php"); | |
// Extract important details from the summarized data | |
$originalMessageCount = $chatData['chat_summary']['original_message_count'] ?? count($messages); | |
$userMessagesText = $chatData['chat_summary']['user_messages_text']; | |
logMessage("Original message count in summary: " . $originalMessageCount); | |
logMessage("User messages text length: " . strlen($userMessagesText)); | |
// Get user information for context | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Format metrics for context if available | |
$metricsContext = []; | |
if (!empty($metrics)) { | |
foreach ($metrics as $metric => $data) { | |
$metricsContext[$metric] = $data['score']; | |
} | |
} | |
// Generate conversation analysis using pre-summarized text | |
$fullText = "Note: This analysis is based on a pre-summarized conversation with {$originalMessageCount} messages.\n\n" . $userMessagesText; | |
$analysis = analyzeText($fullText, "conversation_analysis", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'title' => $userTitle, | |
'company' => $userCompany, | |
'metrics' => $metricsContext, | |
'is_summarized' => true | |
]); | |
// Generate language style analysis based on user's language from the summary | |
$languageStyle = analyzeText($userMessagesText, "language_style", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metricsContext, | |
'is_summarized' => true | |
]); | |
// Generate character analysis using the summarized text | |
$characterAnalysis = analyzeText($fullText, "character_analysis", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'title' => $userTitle, | |
'metrics' => $metricsContext, | |
'is_summarized' => true | |
]); | |
// Return the generated summary | |
return [ | |
'analysis' => $analysis, | |
'language_style' => $languageStyle, | |
'character_analysis' => $characterAnalysis, | |
'used_summary' => true | |
]; | |
} | |
// If no pre-summarized data is available, continue with regular processing | |
// Check if we have enough messages to analyze | |
if (empty($messages) || count($messages) < 2) { | |
$error = "Sohbet özeti oluşturulamadı: Yeterli mesaj bulunamadı! Mesaj sayısı: " . count($messages); | |
logMessage("ERROR: " . $error); | |
throw new Exception($error); | |
} | |
// Find first user message index | |
$firstUserMessageIndex = -1; | |
foreach ($messages as $index => $msg) { | |
if (isset($msg['role']) && $msg['role'] === 'user') { | |
$firstUserMessageIndex = $index; | |
break; | |
} | |
} | |
// Skip the user's first message | |
$startIndex = ($firstUserMessageIndex >= 0) ? $firstUserMessageIndex + 1 : 0; | |
// Include both user and system/assistant messages for a comprehensive analysis | |
$relevantMessages = array_slice($messages, $startIndex); | |
// Extract user messages for specific user-focused analysis | |
$userMessages = array_filter($relevantMessages, function($msg) { | |
return isset($msg['role']) && $msg['role'] === 'user'; | |
}); | |
// Log some debug info about messages | |
logMessage("Total messages: " . count($messages) . ", Relevant messages: " . count($relevantMessages) . ", User messages: " . count($userMessages)); | |
if (count($userMessages) < 1) { | |
$error = "Kullanıcıya ait mesaj bulunamadı!"; | |
logMessage("ERROR: " . $error); | |
throw new Exception($error); | |
} | |
// Check message count | |
$messageCount = count($relevantMessages); | |
$isVeryLargeConversation = $messageCount > 100; | |
$isLargeConversation = $messageCount > 50; | |
logMessage("Conversation size check: {$messageCount} messages, very large: " . ($isVeryLargeConversation ? "yes" : "no") . ", large: " . ($isLargeConversation ? "yes" : "no")); | |
// For very large conversations, use summarization approach | |
if ($isVeryLargeConversation) { | |
logMessage("Using summarization for very large conversation"); | |
// Generate a summary of the conversation | |
$summary = summarizeChatContent($relevantMessages, $userData); | |
// Create artificial user and assistant messages from the summary | |
$artificialMessages = [ | |
[ | |
'role' => 'system', | |
'content' => "Note: This is a summarized version of a conversation with {$messageCount} messages." | |
], | |
[ | |
'role' => 'assistant', | |
'content' => "The following is a summary of our conversation: " | |
], | |
[ | |
'role' => 'user', | |
'content' => $summary | |
] | |
]; | |
// Use the summarized version for analysis | |
$relevantMessages = $artificialMessages; | |
// Update the user messages with the summary | |
$userMessages = array_filter($relevantMessages, function($msg) { | |
return isset($msg['role']) && $msg['role'] === 'user'; | |
}); | |
} | |
// For large (but not very large) conversations, truncate the messages | |
else if ($isLargeConversation) { | |
logMessage("Using message truncation for large conversation"); | |
$relevantMessages = processMessagesForAnalysis($relevantMessages); | |
// Update the user messages with the processed set | |
$userMessages = array_filter($relevantMessages, function($msg) { | |
return isset($msg['role']) && $msg['role'] === 'user'; | |
}); | |
} | |
// Combine all relevant messages into a single text for analysis | |
$fullText = ''; | |
foreach ($relevantMessages as $msg) { | |
$role = $msg['role'] ?? 'unknown'; | |
$content = $msg['content'] ?? ''; | |
$fullText .= "[$role]: $content\n\n"; | |
} | |
// Combine user messages into a single text for user-specific analysis | |
$userText = ''; | |
foreach ($userMessages as $msg) { | |
$userText .= ($msg['content'] ?? '') . "\n"; | |
} | |
// Get user information for context | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Format metrics for context if available | |
$metricsContext = []; | |
if (!empty($metrics)) { | |
foreach ($metrics as $metric => $data) { | |
$metricsContext[$metric] = $data['score']; | |
} | |
} | |
// Generate conversation analysis using all relevant messages | |
$analysis = analyzeText($fullText, "conversation_analysis", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'title' => $userTitle, | |
'company' => $userCompany, | |
'metrics' => $metricsContext | |
]); | |
// Generate language style analysis based on user's language | |
$languageStyle = analyzeText($userText, "language_style", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metricsContext | |
]); | |
// Generate character analysis using the full conversation | |
$characterAnalysis = analyzeText($fullText, "character_analysis", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'title' => $userTitle, | |
'metrics' => $metricsContext | |
]); | |
// Return the generated summary | |
return [ | |
'analysis' => $analysis, | |
'language_style' => $languageStyle, | |
'character_analysis' => $characterAnalysis | |
]; | |
} | |
function generateInsights($userData, $messages, $answers, $metrics, $chatData = null) { | |
logMessage("Generating AI insights"); | |
// Check if we have pre-summarized chat data | |
if ($chatData && isset($chatData['chat_summary']) && isset($chatData['chat_summary']['user_messages_text'])) { | |
logMessage("Using pre-summarized user messages text for insights"); | |
$userMessagesText = $chatData['chat_summary']['user_messages_text']; | |
} else { | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Check if we have enough data to analyze | |
if (empty($answers)) { | |
$error = "Değerlendirme verileri bulunamadı!"; | |
logMessage("ERROR: " . $error); | |
throw new Exception($error); | |
} | |
logMessage("Found " . count($answers) . " assessment answers"); | |
// Count messages to determine if we need to limit the text | |
$messageCount = count($messages); | |
$isLargeMessageSet = $messageCount > 50; | |
logMessage("Processing {$messageCount} messages for insights generation, large set: " . ($isLargeMessageSet ? "yes" : "no")); | |
// Extract relevant text from messages with limitation for large sets | |
$userMessagesText = ""; | |
$userMessageCount = 0; | |
$maxUserMessages = $isLargeMessageSet ? 25 : 100; // Limit to 25 messages if large set | |
foreach ($messages as $message) { | |
if (isset($message['role']) && $message['role'] === 'user' && isset($message['content'])) { | |
// For large sets, only include a limited number of user messages | |
if ($userMessageCount < $maxUserMessages) { | |
$userMessagesText .= $message['content'] . "\n"; | |
$userMessageCount++; | |
} | |
} | |
} | |
// If we limited the messages, add a note | |
if ($userMessageCount >= $maxUserMessages && $isLargeMessageSet) { | |
$userMessagesText .= "\n[Note: " . ($messageCount - $userMessageCount) . " additional messages were excluded due to size constraints]\n"; | |
logMessage("Limited user messages for insights to {$userMessageCount} of {$messageCount} total messages"); | |
} | |
} | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Combine answers into context for AI | |
$answersText = ""; | |
foreach ($answers as $question => $answer) { | |
$answersText .= "Soru: {$question}\nCevap: {$answer}\n\n"; | |
} | |
// Format metrics for AI context | |
$metricsText = ""; | |
foreach ($metrics as $metric => $data) { | |
$metricsText .= "{$metric}: {$data['score']}/10 - {$data['description']}\n"; | |
} | |
// Generate various insights | |
$strengthsWeaknesses = analyzeText($userMessagesText . "\n" . $answersText . "\n" . $metricsText, | |
"strengths_weaknesses", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'title' => $userTitle, | |
'company' => $userCompany, | |
'metrics' => $metrics, | |
'is_summarized' => isset($chatData['chat_summary']) | |
] | |
); | |
$technologyApproach = analyzeText($userMessagesText . "\n" . $answersText . "\n" . $metricsText, | |
"technology_approach", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metrics, | |
'is_summarized' => isset($chatData['chat_summary']) | |
] | |
); | |
$decisionMaking = analyzeText($userMessagesText . "\n" . $answersText . "\n" . $metricsText, | |
"decision_making", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metrics, | |
'is_summarized' => isset($chatData['chat_summary']) | |
] | |
); | |
$communicationStyle = analyzeText($userMessagesText . "\n" . $answersText . "\n" . $metricsText, | |
"communication_style", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metrics, | |
'is_summarized' => isset($chatData['chat_summary']) | |
] | |
); | |
$digitalHabits = analyzeText($userMessagesText . "\n" . $answersText . "\n" . $metricsText, | |
"digital_habits", [ | |
'name' => $userName, | |
'surname' => $userSurname, | |
'metrics' => $metrics, | |
'is_summarized' => isset($chatData['chat_summary']) | |
] | |
); | |
// Return all insights | |
return [ | |
'strengths_weaknesses' => $strengthsWeaknesses, | |
'technology_approach' => $technologyApproach, | |
'decision_making' => $decisionMaking, | |
'communication_style' => $communicationStyle, | |
'digital_habits' => $digitalHabits | |
]; | |
} | |
function calculateMetrics($answers) { | |
logMessage("Calculating metrics from assessment answers"); | |
if (empty($answers)) { | |
logMessage("No answers provided for metric calculation"); | |
return []; | |
} | |
// Debug: Log the answers we received to ensure proper data | |
logMessage("Raw answers data: " . json_encode($answers)); | |
// Define metrics with descriptions - one for each question | |
$metrics = [ | |
'sezgisel_karar' => [ | |
'score' => 0, | |
'description' => 'Sezgisel kararlar verme eğilimi', | |
'question_index' => 0 | |
], | |
'otomasyon_yatkinligi' => [ | |
'score' => 0, | |
'description' => 'Otomatik çözümleri benimseme yatkınlığı', | |
'question_index' => 1 | |
], | |
'degisim_direnci' => [ | |
'score' => 0, | |
'description' => 'Teknolojik değişime direnç gösterme seviyesi', | |
'question_index' => 2 | |
], | |
'veriyle_iletisim' => [ | |
'score' => 0, | |
'description' => 'Verilerle iletişim kurma ve sunma becerisi', | |
'question_index' => 3 | |
], | |
'bagimli_kullanim' => [ | |
'score' => 0, | |
'description' => 'Dijital işlerde başkalarına bağımlı olma eğilimi', | |
'question_index' => 4 | |
], | |
'ekip_ici_dijital_aliskanlik' => [ | |
'score' => 0, | |
'description' => 'Ekip içi dijital sistemleri kullanma alışkanlığı', | |
'question_index' => 5 | |
], | |
'capraz_dijital_merak' => [ | |
'score' => 0, | |
'description' => 'Farklı alanlardaki dijital gelişmelere duyulan merak', | |
'question_index' => 6 | |
], | |
'bagimsiz_veri_erisimi' => [ | |
'score' => 0, | |
'description' => 'Bağımsız olarak veri sistemlerine erişim ve kullanım becerisi', | |
'question_index' => 7 | |
], | |
'gec_benimseyici' => [ | |
'score' => 0, | |
'description' => 'Yeni teknolojileri geç benimseme eğilimi', | |
'question_index' => 8 | |
], | |
'dijitalde_yardim_bagimliligi' => [ | |
'score' => 0, | |
'description' => 'Dijital araçları kullanmada yardım alma ihtiyacı', | |
'question_index' => 9 | |
], | |
'dijital_ogrenme_sikligi' => [ | |
'score' => 0, | |
'description' => 'Yeni dijital yöntemleri öğrenme sıklığı', | |
'question_index' => 10 | |
], | |
'sozlu_iletisim_tercihi' => [ | |
'score' => 0, | |
'description' => 'Veri yerine hikaye anlatımını tercih etme eğilimi', | |
'question_index' => 11 | |
], | |
'erken_deneyici' => [ | |
'score' => 0, | |
'description' => 'Yeni araçları erken deneme ve benimseme eğilimi', | |
'question_index' => 12 | |
], | |
'sezgi_ustunlugu' => [ | |
'score' => 0, | |
'description' => 'Veri yerine sezgilere öncelik verme eğilimi', | |
'question_index' => 13 | |
], | |
'dijital_kullanim_tercihi' => [ | |
'score' => 0, | |
'description' => 'Dijital sistemleri tercih etme ve kullanma eğilimi', | |
'question_index' => 14 | |
], | |
'teknik_ogrenme_direnci' => [ | |
'score' => 0, | |
'description' => 'Yeni sistemleri öğrenmeye karşı gösterilen direnç', | |
'question_index' => 15 | |
], | |
'pozitif_dijital_algi' => [ | |
'score' => 0, | |
'description' => 'Teknolojiye karşı pozitif algı ve tutum', | |
'question_index' => 16 | |
], | |
'manuel_guven_egilimi' => [ | |
'score' => 0, | |
'description' => 'Dijital çözümler yerine manuel yöntemleri tercih etme', | |
'question_index' => 17 | |
], | |
'dis_alan_direnci' => [ | |
'score' => 0, | |
'description' => 'Uzmanlık alanı dışındaki alanlara girmekten kaçınma', | |
'question_index' => 18 | |
], | |
'statuko_tercihi' => [ | |
'score' => 0, | |
'description' => 'Mevcut sistemleri koruma ve değişime direnç gösterme', | |
'question_index' => 19 | |
] | |
]; | |
// Process each answer - handle both indexed arrays and associative arrays | |
$answerArray = array(); | |
// If the answers are in an associative array with question text as keys | |
if (is_array($answers) && !empty($answers) && !isset($answers[0])) { | |
logMessage("Handling associative array of answers with question text as keys"); | |
$i = 0; | |
foreach ($answers as $question => $answer) { | |
$answerArray[$i] = $answer; | |
$i++; | |
} | |
} else { | |
// If the answers are already in an indexed array | |
$answerArray = is_array($answers) ? $answers : array_values((array)$answers); | |
logMessage("Using indexed array of answers"); | |
} | |
// Debug: Log the processed answer array | |
logMessage("Processed answer array: " . json_encode($answerArray)); | |
foreach ($metrics as $metricKey => &$metricData) { | |
$questionIndex = $metricData['question_index']; | |
// If we have an answer for this question | |
if (isset($answerArray[$questionIndex])) { | |
// Make sure the answer is a numeric value | |
$rawAnswer = is_numeric($answerArray[$questionIndex]) ? | |
floatval($answerArray[$questionIndex]) : 4; | |
// Scale the answer (originally 0-8) to 0-10 | |
$scaledAnswer = ($rawAnswer / 8) * 10; | |
$metricData['score'] = round($scaledAnswer, 1); | |
$metricData['raw_score'] = $rawAnswer; | |
logMessage("Metric {$metricKey} (Q" . ($questionIndex+1) . "): raw={$rawAnswer}, scaled={$metricData['score']}"); | |
} else { | |
// Default value if no answer | |
$metricData['score'] = 5.0; | |
$metricData['raw_score'] = 4; | |
logMessage("Metric {$metricKey} (Q" . ($questionIndex+1) . "): No answer found, using default"); | |
} | |
} | |
logMessage("Calculated " . count($metrics) . " metrics"); | |
return $metrics; | |
} | |
function analyzeText($text, $analysisType, $context = []) { | |
logMessage("Analyzing text for: " . $analysisType); | |
// Try to use OpenAI API first | |
try { | |
$result = callOpenAIAPI($text, $analysisType, $context); | |
if (!empty($result['text'])) { | |
return $result['text']; | |
} | |
} catch (Exception $e) { | |
logMessage("OpenAI API error: " . $e->getMessage()); | |
} | |
// If OpenAI fails, use local fallback | |
return localAnalysisFallback($text, $analysisType, $context); | |
} | |
function callOpenAIAPI($text, $analysisType, $context = []) { | |
$apiKey = getApiKeyFromConfig(); | |
// Build prompt based on analysis type | |
$prompt = buildPrompt($text, $analysisType, $context); | |
try { | |
// Get configuration settings from app.php | |
$appConfigFile = __DIR__ . '/config/app.php'; | |
$model = 'gpt-4.1'; // Default model | |
$endpointUrl = 'https://api.openai.com/v1/responses'; // Default endpoint | |
$maxTokens = 6273; // Default max tokens | |
if (file_exists($appConfigFile)) { | |
$appConfig = require $appConfigFile; | |
if (isset($appConfig['openai'])) { | |
$model = $appConfig['openai']['model'] ?? $model; | |
$endpointUrl = $appConfig['openai']['endpoint_url'] ?? $endpointUrl; | |
$maxTokens = $appConfig['openai']['max_output_tokens'] ?? $maxTokens; | |
logMessage("Using OpenAI settings from app.php: model=$model, maxTokens=$maxTokens"); | |
} | |
} | |
// Format the request payload according to the required format | |
$payload = [ | |
'model' => $model, | |
'input' => $prompt, | |
'text' => [ | |
'format' => ['type' => 'text'] | |
], | |
'reasoning' => (object)[], | |
'tools' => [], | |
'temperature' => 1, | |
'max_output_tokens' => $maxTokens, | |
'top_p' => 1, | |
'store' => true, | |
]; | |
// Initialize cURL | |
$ch = curl_init($endpointUrl); | |
curl_setopt_array($ch, [ | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_HTTPHEADER => [ | |
'Content-Type: application/json', | |
"Authorization: Bearer {$apiKey}" | |
], | |
CURLOPT_POST => true, | |
CURLOPT_POSTFIELDS => json_encode($payload), | |
CURLOPT_TIMEOUT => 120 // Increased timeout for larger responses | |
]); | |
// Send the request | |
$response = curl_exec($ch); | |
// Check for cURL errors | |
if ($err = curl_error($ch)) { | |
curl_close($ch); | |
throw new RuntimeException("cURL error: {$err}"); | |
} | |
// Get HTTP status code | |
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
curl_close($ch); | |
// Handle non-200 status codes | |
if ($httpCode !== 200) { | |
throw new RuntimeException("API returned HTTP code {$httpCode}: {$response}"); | |
} | |
// Parse response | |
$result = json_decode($response, true); | |
if (!$result) { | |
throw new RuntimeException("Failed to parse API response: " . json_last_error_msg()); | |
} | |
// Extract text from the output | |
$extractedText = ""; | |
if (isset($result['output']) && is_array($result['output'])) { | |
foreach ($result['output'] as $output) { | |
if (isset($output['type']) && $output['type'] === 'message' && | |
isset($output['content']) && is_array($output['content'])) { | |
foreach ($output['content'] as $content) { | |
if (isset($content['text'])) { | |
$extractedText = $content['text']; | |
break 2; // Break both loops once text is found | |
} | |
} | |
} | |
} | |
} | |
logMessage("Successfully received OpenAI response using model: $model"); | |
return [ | |
'text' => $extractedText, | |
'full_result' => $result | |
]; | |
} catch (Exception $e) { | |
// Try using Claude model if OpenAI fails | |
try { | |
logMessage("OpenAI API error, trying Claude as fallback: " . $e->getMessage()); | |
return callClaudeAPI($prompt); | |
} catch (Exception $claudeException) { | |
logMessage("Claude API failed too: " . $claudeException->getMessage()); | |
// Return empty result, local fallback will handle it | |
return [ | |
'text' => '', | |
'full_result' => [] | |
]; | |
} | |
} | |
} | |
function callClaudeAPI($prompt) { | |
// This is a placeholder for a Claude integration | |
// Actual implementation would depend on the Claude API requirements | |
logMessage("Claude API integration not implemented yet"); | |
return [ | |
'text' => '', | |
'full_result' => [] | |
]; | |
} | |
function getApiKeyFromConfig() { | |
// Try to get from environment first | |
$apiKey = getenv('OPENAI_API_KEY'); | |
if ($apiKey) { | |
logMessage("Using OpenAI API key from environment variable"); | |
return $apiKey; | |
} | |
// Try to get from app.php first | |
$appConfigFile = __DIR__ . '/config/app.php'; | |
if (file_exists($appConfigFile)) { | |
$appConfig = require $appConfigFile; | |
if (isset($appConfig['openai']) && isset($appConfig['openai']['api_key'])) { | |
logMessage("Using OpenAI API key from app.php"); | |
return $appConfig['openai']['api_key']; | |
} | |
} | |
// Try to get from config.php as fallback | |
$configFile = __DIR__ . '/config/config.php'; | |
if (file_exists($configFile)) { | |
include $configFile; | |
if (isset($config['openai_api_key'])) { | |
logMessage("Using OpenAI API key from config.php"); | |
return $config['openai_api_key']; | |
} | |
} | |
// Fallback to empty key (not recommended for production) | |
logMessage("WARNING: No OpenAI API key found in configuration files"); | |
return ''; | |
} | |
function buildPrompt($text, $analysisType, $context = []) { | |
$userName = $context['name'] ?? 'Kullanıcı'; | |
$isSummarized = isset($context['is_summarized']) && $context['is_summarized']; | |
// Add information about summarization to the prompt if relevant | |
$summarizedNote = $isSummarized ? | |
"Not: Bu analiz özetlenmiş bir sohbet verisine dayanmaktadır. Temel eğilimler korunmuş olsa da, bazı nüanslar eksik olabilir." : ""; | |
$promptTemplates = [ | |
'conversation_analysis' => "Analiz: Aşağıdaki konuşmayı detaylı olarak değerlendir ve kullanıcının ({$userName}) karakteri, düşünce yapısı ve yaklaşımları hakkında kapsamlı bir analiz yap. | |
Konuşma içindeki hem sistem soruları hem de kullanıcı yanıtlarını dikkate al. | |
Lütfen objektif ve yapıcı ol. | |
Kullanıcının fikirlerini ifade etme biçimine, sorulara yaklaşımına ve iletişim tarzına dikkat et. | |
Analizin en fazla 120 kelime uzunluğunda olmalıdır. Başlığı veya sonucu özetleme yok, doğrudan analize başla. | |
{$summarizedNote} | |
\n\nKullanıcı: {$userName}\n\nKonuşma:\n{$text}\n\nKonuşma Analizi:", | |
'language_style' => "Analiz: Aşağıdaki konuşmada kullanıcının ({$userName}) dil ve ifade tarzı hakkında detaylı bir analiz yap. | |
İletişim şekli, kelime seçimleri, cümle yapısı ve kendini ifade etme biçimine odaklan. | |
Kullanıcının dil kullanımındaki belirgin özellikleri, resmiyet seviyesi, kelime dağarcığı zenginliği ve ifade netliğini değerlendir. | |
Analizin en fazla 120 kelime uzunluğunda olmalıdır. Başlığı veya sonucu özetleme yok, doğrudan analize başla. | |
{$summarizedNote} | |
\n\nKullanıcı: {$userName}\n\nMetin:\n{$text}\n\nDil ve Düşünce Tarzı:", | |
'character_analysis' => "Analiz: Aşağıdaki konuşmaya dayanarak kullanıcının ({$userName}) karakter özellikleri hakkında kapsamlı bir değerlendirme yap. | |
Kişilik özellikleri, karar verme biçimi, problem çözme yaklaşımı ve profesyonel eğilimlere odaklan. | |
Kullanıcının düşünce yapısını, analitik veya sezgisel yönelimini, risk alma eğilimini ve değer verdiği konuları değerlendir. | |
Hem sistem sorularına hem de kullanıcı yanıtlarına dikkat ederek bütünsel bir karakter analizi oluştur. | |
Analizin en fazla 120 kelime uzunluğunda olmalıdır. Başlığı veya sonucu özetleme yok, doğrudan analize başla. | |
{$summarizedNote} | |
\n\nKullanıcı: {$userName}\n\nKonuşma:\n{$text}\n\nKarakter Analizi:", | |
'strengths_weaknesses' => "Analiz: Aşağıdaki konuşma ve değerlendirme yanıtlarına göre kullanıcının dijital dünyada güçlü ve gelişmeye açık yönlerini belirle. Nesnel ve yapıcı ol. En fazla 120 kelime kullan.\n\nKullanıcı: {$userName}\n\nVeriler:\n{$text}\n\nGüçlü ve Gelişmeye Açık Yönler:", | |
'technology_approach' => "Analiz: Aşağıdaki konuşma ve değerlendirme yanıtlarına göre kullanıcının teknolojiye yaklaşımını, dijital araçları kullanma biçimini ve teknolojik değişimlere adaptasyonunu değerlendir. En fazla 120 kelime kullan.\n\nKullanıcı: {$userName}\n\nVeriler:\n{$text}\n\nTeknoloji Yaklaşımı:", | |
'decision_making' => "Analiz: Aşağıdaki konuşma ve değerlendirme yanıtlarına göre kullanıcının karar verme mekanizmalarını, veri kullanımını ve problem çözme yaklaşımını değerlendir. En fazla 120 kelime kullan.\n\nKullanıcı: {$userName}\n\nVeriler:\n{$text}\n\nKarar Verme Mekanizması:", | |
'communication_style' => "Analiz: Aşağıdaki konuşma ve değerlendirme yanıtlarına göre kullanıcının iletişim tarzını, ifade biçimini ve ekip içi iletişim yaklaşımını değerlendir. En fazla 120 kelime kullan.\n\nKullanıcı: {$userName}\n\nVeriler:\n{$text}\n\nİletişim Tarzı:", | |
'digital_habits' => "Analiz: Aşağıdaki konuşma ve değerlendirme yanıtlarına göre kullanıcının dijital alışkanlıklarını, teknoloji kullanım rutinlerini ve dijital dünyadaki tercihlerini değerlendir. En fazla 120 kelime kullan.\n\nKullanıcı: {$userName}\n\nVeriler:\n{$text}\n\nDijital Alışkanlıklar:" | |
]; | |
if (!isset($promptTemplates[$analysisType])) { | |
return "Analiz: Bu metni değerlendir ve objektif bir analiz yap. En fazla 120 kelime kullan.\n\nMetin:\n{$text}\n\nAnaliz:"; | |
} | |
return $promptTemplates[$analysisType]; | |
} | |
function localAnalysisFallback($text, $analysisType, $context = []) { | |
$userName = $context['name'] ?? 'Kullanıcı'; | |
$fallbackResponses = [ | |
'conversation_analysis' => "{$userName}, konuşmalarında net ve öz bir iletişim tarzı benimsiyor. Düşüncelerini organize şekilde ifade ediyor, sorunlara pratik çözümler getiriyor. Sorulara verdiği yanıtlarda analitik bir yaklaşım sergileyerek konuya hakimiyetini gösteriyor. Teknolojiye yaklaşımı pragmatik; yeni teknolojileri benimsemekte temkinli ancak açık fikirli bir tutum sergiliyor. İş süreçlerinde verimlilik odaklı ve sistemli çalışmayı tercih ediyor.", | |
'language_style' => "{$userName} kısa ve öz cümleler kullanarak iletişim kuruyor. Teknik terimlere hakimiyeti var ve düşüncelerini doğrudan ifade etme eğiliminde. Resmi dil yapılarından çok günlük, pratik bir dil kullanımı tercih ediyor. Kelime seçimlerinde net ve anlaşılır olmayı önemsiyor. Soru-cevap formatında daha rahat iletişim kuruyor ve düşüncelerini daha sistematik ifade edebiliyor.", | |
'character_analysis' => "{$userName}, analitik düşünme eğilimi gösteren, problem çözme odaklı bir kişi. Karar verme süreçlerinde hem veri hem deneyime değer veriyor. İş odaklı ve pratik yaklaşımları benimsiyor, ekip çalışmasında işbirliğine açık bir tutum sergiliyor. Yeni teknolojileri değerlendirirken fayda-maliyet analizi yapma eğiliminde. Detaylara önem veriyor ancak bazen büyük resmi görmekte zorlanabiliyor. Öğrenmeye açık ve kendini geliştirme konusunda istekli.", | |
'strengths_weaknesses' => "Güçlü Yönler: Pratik problem çözme yeteneği, analitik düşünme becerisi, işe yönelik pragmatik yaklaşım, öz ifade gücü, teknolojik adaptasyon becerisi, detay odaklı çalışma disiplini.\n\nGelişime Açık Alanlar: Yeni teknolojilere adaptasyon sürecini hızlandırma, dijital araçların daha yaratıcı kullanımı, teknik detaylardan önce büyük resmi görme becerisi, iş süreçlerinde daha esnek yaklaşımlar geliştirme.", | |
'technology_approach' => "{$userName} teknolojiye pragmatik yaklaşıyor; öncelikle işe yararlılık ve verimlilik açısından değerlendiriyor. Yeni teknolojileri benimsemede kontrollü ve temkinli; önce kanıtlanmış çözümleri tercih ediyor. Dijital araçları iş akışını kolaylaştırmak için kullanıyor, süreçleri optimize etmeye önem veriyor. Karmaşık sistemlerden ziyade sade ve kullanımı kolay araçları tercih ediyor. Teknolojik değişimlere uyum sağlama kapasitesi yüksek.", | |
'decision_making' => "{$userName} karar verirken hem analitik verilere hem de kişisel deneyime başvuruyor. Önemli kararlarda çeşitli faktörleri dengeli bir şekilde değerlendirme eğiliminde. Acil durumlardan ziyade, planlı ve düşünülmüş kararları tercih ediyor. Riskleri minimize etmeye çalışırken, fırsatları değerlendirmek için pratik yaklaşımlar geliştiriyor. Karar süreçlerinde veri temelli analiz yapmayı önemsiyor.", | |
'communication_style' => "{$userName} iletişimde doğrudan ve pragmatik bir yaklaşım benimsiyor. Fikirlerini özlü bir şekilde ifade ediyor, gereksiz detaylardan kaçınıyor. Ekip içi iletişimde işbirlikçi ve çözüm odaklı, ancak bazen teknik detayları aktarmada zorlanabilir. Dijital iletişim araçlarını etkili kullanıyor, yazılı iletişimde net ve organize. Sunumlarında veri ve somut örneklerle desteklemeyi tercih ediyor.", | |
'digital_habits' => "{$userName} dijital araçları günlük rutininde düzenli kullanıyor, özellikle temel ofis uygulamalarına hakimiyeti var. İş süreçlerinde dijital çözümleri pratik faydaları için benimsiyor. Sosyal medya ve yeni uygulamalara yaklaşımı temkinli; öncelikle iş ihtiyaçlarına odaklanıyor. Teknolojik yenilikleri takip ediyor ama erken benimseyicilerden değil, kanıtlanmış dijital çözümleri tercih ediyor. Veri yönetiminde sistematik bir yaklaşım sergiliyor." | |
]; | |
// Return fallback response or generic message if no template exists | |
return $fallbackResponses[$analysisType] ?? | |
"{$userName} ile ilgili yapılan analizde sistemsel bir hata nedeniyle detaylı değerlendirme üretilemedi. Kullanıcının genel olarak pragmatik ve analitik bir yaklaşım sergilediği, teknolojik araçları iş süreçlerini iyileştirmek için kullandığı, iletişimde açık ve net bir tarz benimsediği gözlemlenmektedir."; | |
} | |
function generatePDFReport($userData, $messages, $answers, $metrics, $summary, $insights) { | |
logMessage("Generating PDF report"); | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userFullName = $userName . ' ' . $userSurname; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Create report directory if it doesn't exist | |
$reportDir = 'reports'; | |
if (!is_dir($reportDir)) { | |
mkdir($reportDir, 0755, true); | |
} | |
// Generate unique filename for the report | |
$timestamp = time(); | |
$safeName = preg_replace('/[^a-z0-9_-]/i', '_', $userFullName); | |
$filename = $reportDir . '/POLARIS_' . $safeName . '_' . $timestamp . '.pdf'; | |
try { | |
// Use mPDF to generate report | |
require_once __DIR__ . '/vendor/autoload.php'; | |
// Initialize mPDF with enhanced Unicode and emoji support | |
$mpdf = new \Mpdf\Mpdf([ | |
'mode' => 'utf-8', | |
'format' => 'A4', | |
'margin_left' => 15, | |
'margin_right' => 15, | |
'margin_top' => 15, | |
'margin_bottom' => 15, | |
'default_font' => 'freesans', | |
'autoPageBreak' => true, | |
'setAutoTopMargin' => 'stretch', | |
'setAutoBottomMargin' => 'stretch', | |
'shrink_tables_to_fit' => 1, | |
'use_kwt' => true, | |
'keep_table_proportions' => true, | |
'img_dpi' => 96, | |
'curlTimeout' => 10, | |
// Enhanced Unicode support | |
'useSubstitutions' => true, | |
'simpleTables' => true, | |
'packTableData' => true, | |
'adjustFontDescLineheight' => 1.2 | |
]); | |
// Set Unicode fonts and font subsetting for better character support | |
$mpdf->useAdobeCJK = true; | |
$mpdf->autoScriptToLang = true; | |
$mpdf->autoLangToFont = true; | |
// Set document metadata | |
$mpdf->SetTitle('POLARIS Dijital Yetenek Raporu - ' . $userFullName); | |
$mpdf->SetAuthor('iWise'); | |
$mpdf->SetCreator('POLARIS'); | |
// Include Font Awesome CSS for icons - with improved compatibility | |
$fontAwesomeCss = ' | |
@font-face { | |
font-family: "FontAwesome"; | |
font-weight: normal; | |
font-style: normal; | |
src: url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/webfonts/fa-solid-900.ttf") format("truetype"); | |
} | |
'; | |
// Build HTML content for the report | |
$html = buildReportHTML($userData, $messages, $answers, $metrics, $summary, $insights); | |
// Add Font Awesome CSS to the HTML | |
$html = str_replace('</head>', '<style>' . $fontAwesomeCss . '</style></head>', $html); | |
// Replace emoji Unicode characters with simpler alternatives | |
$emojiReplacements = [ | |
'💬' => '<span class="emoji-symbol emoji-comment">[ ]</span>', | |
'🗣️' => '<span class="emoji-symbol emoji-user">(S)</span>', | |
'🧠' => '<span class="emoji-symbol emoji-brain">(B)</span>', | |
'❌' => '<span class="emoji-symbol emoji-error">(X)</span>', | |
'📊' => '<span class="emoji-symbol emoji-chart">(G)</span>', | |
'😊' => '<span class="emoji-symbol emoji-smile">:)</span>', | |
'👍' => '<span class="emoji-symbol emoji-thumbs-up">(+)</span>', | |
'✅' => '<span class="emoji-symbol emoji-check">(✓)</span>', | |
'1️⃣' => '<span style="display:inline-block; background-color:#0071e3; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">1</span>', | |
'2️⃣' => '<span style="display:inline-block; background-color:#34c759; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">2</span>', | |
'3️⃣' => '<span style="display:inline-block; background-color:#ff9f0a; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">3</span>', | |
'4️⃣' => '<span style="display:inline-block; background-color:#5856d6; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">4</span>', | |
'5️⃣' => '<span style="display:inline-block; background-color:#ff3b30; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">5</span>' | |
]; | |
foreach ($emojiReplacements as $emoji => $replacement) { | |
$html = str_replace($emoji, $replacement, $html); | |
} | |
// Alternative text replacements for any emoji that couldn't be processed | |
$emojiToText = [ | |
'💬' => '[KONUŞMA]', | |
'🗣️' => '[KONUŞMACI]', | |
'🧠' => '[BEYİN]', | |
'❌' => '[X]', | |
'📊' => '[GRAFİK]', | |
'😊' => '[GÜLÜMSEME]', | |
'👍' => '[BAŞPARMAK]', | |
'✅' => '[ONAY]', | |
'1️⃣' => '[1]', | |
'2️⃣' => '[2]', | |
'3️⃣' => '[3]', | |
'4️⃣' => '[4]', | |
'5️⃣' => '[5]' | |
]; | |
// Apply text replacement for any remaining emojis | |
foreach ($emojiToText as $emoji => $text) { | |
if (strpos($html, $emoji) !== false) { | |
// Replace any remaining raw emojis with text representations | |
$html = str_replace($emoji, '<span style="font-weight:bold; color:#0071e3;">' . $text . '</span>', $html); | |
} | |
} | |
// Write HTML to PDF | |
$mpdf->WriteHTML($html); | |
// Save PDF to file | |
$mpdf->Output($filename, \Mpdf\Output\Destination::FILE); | |
logMessage("PDF report generated successfully: " . $filename); | |
return $filename; | |
} catch (Exception $e) { | |
$error = "PDF raporu oluşturulurken hata oluştu: " . $e->getMessage(); | |
logMessage("ERROR: " . $error); | |
throw new Exception($error); | |
} | |
} | |
function buildReportHTML($userData, $messages, $answers, $metrics, $summary, $insights) { | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userFullName = $userName . ' ' . $userSurname; | |
$userTitle = $userData['title'] ?? 'Belirtilmemiş'; | |
$userCompany = $userData['company'] ?? 'Belirtilmemiş'; | |
// Current date and time in Turkish format | |
$date = date('d.m.Y H:i'); | |
// Start building HTML with Apple-inspired design | |
$html = ' | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
<title>POLARIS Dijital Yetenek Raporu</title> | |
</head> | |
<body> | |
<div class="header"> | |
<img class="logo" src="images/logo3.png" alt="iWise Logo"> | |
<h1>POLARIS Dijital Yetenek Raporu</h1> | |
<p style="color: #515154;">Tarih: ' . $date . '</p> | |
</div> | |
<div class="section"> | |
<div class="user-info"> | |
<p><strong>İsim:</strong> ' . htmlspecialchars($userFullName) . '</p> | |
<p><strong>Pozisyon:</strong> ' . htmlspecialchars($userTitle) . '</p> | |
<p><strong>Şirket:</strong> ' . htmlspecialchars($userCompany) . '</p> | |
</div> | |
<h2>Konuşma Geçmişi</h2> | |
<div class="chat-history"> | |
<div class="chat-title">POLARIS ile Sohbet Kaydı</div> | |
<div class="chat-messages">'; | |
// Display all messages including system and assistant messages | |
if (!empty($messages)) { | |
foreach ($messages as $message) { | |
$role = $message['role'] ?? 'user'; | |
$content = $message['content'] ?? ''; | |
$timestamp = isset($message['timestamp']) ? date('H:i', $message['timestamp'] / 1000) : ''; | |
$messageClass = $role; | |
$senderName = ''; | |
switch ($role) { | |
case 'system': | |
$senderName = 'Polaris'; | |
break; | |
case 'assistant': | |
$senderName = 'POLARIS'; | |
break; | |
case 'user': | |
$senderName = $userFullName; | |
break; | |
default: | |
$senderName = 'Polaris'; | |
} | |
// Process content to preserve emojis | |
$processedContent = $content; | |
$html .= ' | |
<div class="message ' . $messageClass . '"> | |
<div class="message-sender">' . htmlspecialchars($senderName) . '</div> | |
' . nl2br($processedContent) . ' | |
' . ($timestamp ? '<span class="message-time">' . $timestamp . '</span>' : '') . ' | |
</div>'; | |
} | |
} else { | |
$html .= '<p style="text-align: center; color: #86868b;">Sohbet kaydı bulunamadı.</p>'; | |
} | |
$html .= ' | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2>Konuşma Özeti</h2> | |
<div class="insights-box" style="border-left: 4px solid #0071e3; background-color: rgba(0, 113, 227, 0.03);"> | |
<div class="insights-heading" style="color: #0071e3;">' . convertEmojiToTwemoji('💬 Konuşma Analizi') . '</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1:</div>'], | |
nl2br(htmlspecialchars($summary['analysis'] ?? 'Analiz bilgisi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #34c759; background-color: rgba(52, 199, 89, 0.03);"> | |
<div class="insights-heading" style="color: #34c759;">' . convertEmojiToTwemoji('🗣️ Dil ve Düşünce Tarzı') . '</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1:</div>'], | |
nl2br(htmlspecialchars($summary['language_style'] ?? 'Analiz bilgisi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff9f0a; background-color: rgba(255, 159, 10, 0.03);"> | |
<div class="insights-heading" style="color: #ff9f0a;">' . convertEmojiToTwemoji('🧠 Karakter Analizi') . '</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1:</div>'], | |
nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2>Değerlendirme Sonuçları</h2>'; | |
// Define paired questions using the same mapping as in mailformat.php | |
$pairedQuestions = [ | |
1 => 14, 2 => 18, 3 => 17, 4 => 12, 5 => 10, | |
6 => 15, 7 => 19, 8 => 16, 9 => 13, 10 => 5, | |
11 => 20, 12 => 4, 13 => 9, 14 => 1, 15 => 6, | |
16 => 8, 17 => 3, 18 => 2, 19 => 7, 20 => 11 | |
]; | |
// Define emotion representations for each question | |
$emotionTypes = [ | |
'Sezgisel karar', 'Otomasyon yatkınlığı', 'Veriyle iletişim', 'Bağımlı kullanım', | |
'Ekip içi dijital alışkanlık', 'Çapraz dijital merak', 'Bağımsız veri erişimi', | |
'Geç benimseyici', 'Dijitalde yardım bağımlılığı', 'Dijital öğrenme sıklığı', | |
'Sözlü iletişim tercihi', 'Erken deneyici', 'Sezgi üstünlüğü', 'Dijital kullanım tercihi', | |
'Teknik öğrenme direnci', 'Pozitif dijital algı', 'Manuel güven eğilimi', 'Dış alan direnci', | |
'Statüko tercihi', 'Yenilikçi yaklaşım' | |
]; | |
// Define the 20 questions from grading.php | |
$gradingQuestions = [ | |
"Karar verirken içgüdüyle hareket etmek, çoğu zaman elimdeki verilerden daha rahat hissettiriyor.", | |
"Tekrarlayan bir işi fark ettiğimde, kendi çözümümü üretmeden önce ekipte bu işin kolaylaştırılmış hâli var mı diye sorarım.", | |
"Yeni araçlar genellikle işleri gereksiz yere karmaşıklaştırıyor gibi geliyor.", | |
"Sunumlarımda tablo ve grafiklerle desteklemek bana daha güvenli bir ifade alanı yaratıyor.", | |
"Dijital işlerde genelde kendi başıma ilerlemek yerine çevremdekilere danışırım.", | |
"Ekipte kullanılan ortak dijital sistemlerde görev paylaşımı netse aktif şekilde rol alırım.", | |
"Kendi alanım dışındaki gelişmeleri de takip etmeye çalışırım; bir konu bana uzaksa bile merak ederim.", | |
"İş için gereken veriye ulaşmam gerekiyorsa, önce sistemleri kendim kurcalamayı denerim.", | |
"Yeni çıkan bir dijital aracı önce ekipten biri denesin, ben sonuçlarına göre karar veririm.", | |
"Bir sistemin içinde kaybolmaktansa, biri adım adım anlatsın daha iyi olur.", | |
"Yılda en az bir yeni dijital yöntemi öğrenmek için zaman ayırırım, elimde not almayı da severim.", | |
"Sunumda hikâye anlatmak verilerden daha etkilidir, çünkü insanlar duygularla bağ kurar.", | |
"Yeni araçlara ilk geçenlerden olmayı severim; deneme cesareti insana güç verir.", | |
"Veri varsa bakarım, yoksa içgüdüme güvenirim. Ama önce veri.", | |
"İşi kolaylaştıran dijital sistemleri severim, ama mümkünse sade ve anlaşılır olmalı.", | |
"Yeni sistemleri öğrenmek bana zor geliyor; keşke her şey aynı kalsaydı diyorum bazen.", | |
"Teknoloji işleri hızlandırır, ama bu bazen derinliği azaltıyor olabilir.", | |
"Kendi çözümlerimi üretmek yerine ekipteki hazır yolu kullanmak işimi kolaylaştırıyor.", | |
"Kendi dışımdaki alanlara girmemeye özen gösteririm, her alanın uzmanı ayrıdır.", | |
"Yeni araçlara vakit ayırmaktan çok, mevcut sistemle ilerlemeyi tercih ederim." | |
]; | |
// Process answers regardless of format | |
$processedAnswers = []; | |
if (!empty($answers)) { | |
$answersArray = is_array($answers) ? $answers : array_values((array)$answers); | |
// If answers are in associative form with questions as keys | |
if (is_string(key($answersArray)) && count($answersArray) <= 20) { | |
foreach ($gradingQuestions as $i => $question) { | |
// Try to find the answer for this question | |
$answer = null; | |
foreach ($answersArray as $q => $a) { | |
if (stripos($q, substr($question, 0, 30)) !== false) { | |
$answer = $a; | |
break; | |
} | |
} | |
$processedAnswers[$i] = $answer ?? 4; // Default to middle value if not found | |
} | |
} | |
// If answers are in indexed array | |
else { | |
for ($i = 0; $i < 20; $i++) { | |
$processedAnswers[$i] = $answersArray[$i] ?? 4; // Default to middle value if not found | |
} | |
} | |
} else { | |
// If no answers at all, create defaults | |
for ($i = 0; $i < 20; $i++) { | |
$processedAnswers[$i] = 4; // Default to middle value | |
} | |
} | |
$html .= '<div class="assessment-container"> | |
<div class="assessment-heading">Değerlendirme Yanıtları</div>'; | |
// Display answers in the new modern style | |
for ($i = 0; $i < 20 && isset($processedAnswers[$i]); $i++) { | |
$question = $gradingQuestions[$i]; | |
$answer = $processedAnswers[$i]; | |
$questionNumber = $i + 1; | |
$html .= '<div class="answer-item"> | |
<div class="answer-question">Soru ' . $questionNumber . ': ' . htmlspecialchars($question) . '</div>'; | |
// Add paired question information if available | |
if (isset($pairedQuestions[$questionNumber])) { | |
$pairedNumber = $pairedQuestions[$questionNumber]; | |
$pairedIndex = $pairedNumber - 1; | |
$pairedAnswer = isset($processedAnswers[$pairedIndex]) ? $processedAnswers[$pairedIndex] : null; | |
if ($pairedAnswer !== null) { | |
// Calculate score difference and determine if there's a conflict | |
$scoreDifference = abs((int)$answer - (int)$pairedAnswer); | |
$conflictEmoji = ($scoreDifference >= 4) ? ' ' . convertEmojiToTwemoji('❌') : ''; | |
$html .= '<div class="answer-paired"><strong>Eş olduğu soru:</strong> Soru ' . $pairedNumber; | |
if ($scoreDifference >= 4) { | |
$html .= ' <span class="answer-conflict">(Çelişkili yanıt' . $conflictEmoji . ')</span>'; | |
} | |
$html .= '</div>'; | |
} | |
} | |
$html .= '<div class="answer-meta">'; | |
// Add emotion type if available | |
if (isset($emotionTypes[$i])) { | |
$html .= '<div class="answer-emotion"><strong>Temsil ettiği duygu:</strong> ' . htmlspecialchars($emotionTypes[$i]) . '</div>'; | |
} | |
$html .= '<div class="answer-score">Puan: <span>' . htmlspecialchars($answer) . '</span>/8</div>'; | |
$html .= '</div></div>'; | |
} | |
$html .= '</div> | |
<h2><i class="fa-brain" style="color:#ff9f0a; font-size:1.2em;"></i> Dijital Yatkınlık Profili</h2> | |
<p style="color: #86868b; font-style: italic; margin-bottom: 20px;">Değerlendirme yanıtlarına göre hesaplanan yatkınlık düzeyleri:</p> | |
<!-- Metrics Table with styled layout --> | |
<div class="assessment-container"> | |
<div class="assessment-heading">Detaylı Yatkınlık Ölçümleri</div> | |
<table class="metrics-table"> | |
<thead> | |
<tr> | |
<th>Yatkınlık</th> | |
<th>Puan</th> | |
<th>Seviye</th> | |
</tr> | |
</thead> | |
<tbody>'; | |
// Define metric display names - using Turkish names from the user's list | |
$metricDisplayNames = [ | |
'sezgisel_karar' => 'Sezgisel Karar', | |
'otomasyon_yatkinligi' => 'Otomasyon Yatkınlığı', | |
'degisim_direnci' => 'Değişim Direnci', | |
'veriyle_iletisim' => 'Veriyle İletişim', | |
'bagimli_kullanim' => 'Bağımlı Kullanım', | |
'ekip_ici_dijital_aliskanlik' => 'Ekip İçi Dijital Alışkanlık', | |
'capraz_dijital_merak' => 'Çapraz Dijital Merak', | |
'bagimsiz_veri_erisimi' => 'Bağımsız Veri Erişimi', | |
'gec_benimseyici' => 'Geç Benimseyici', | |
'dijitalde_yardim_bagimliligi' => 'Dijitalde Yardım Bağımlılığı', | |
'dijital_ogrenme_sikligi' => 'Dijital Öğrenme Sıklığı', | |
'sozlu_iletisim_tercihi' => 'Sözlü İletişim Tercihi', | |
'erken_deneyici' => 'Erken Deneyici', | |
'sezgi_ustunlugu' => 'Sezgi Üstünlüğü', | |
'dijital_kullanim_tercihi' => 'Dijital Kullanım Tercihi', | |
'teknik_ogrenme_direnci' => 'Teknik Öğrenme Direnci', | |
'pozitif_dijital_algi' => 'Pozitif Dijital Algı', | |
'manuel_guven_egilimi' => 'Manuel Güven Eğilimi', | |
'dis_alan_direnci' => 'Dış Alan Direnci', | |
'statuko_tercihi' => 'Statüko Tercihi' | |
]; | |
// Sort metrics by question index to maintain the correct order | |
uasort($metrics, function($a, $b) { | |
return $a['question_index'] - $b['question_index']; | |
}); | |
// Organize metrics by question index | |
$organizedMetrics = []; | |
foreach ($metrics as $metric => $data) { | |
$questionIndex = $data['question_index']; | |
$organizedMetrics[$questionIndex] = [ | |
'name' => $metricDisplayNames[$metric] ?? ucfirst(str_replace('_', ' ', $metric)), | |
'score' => $data['score'], | |
'raw_score' => $data['raw_score'] ?? 0, | |
'description' => $data['description'] ?? '' | |
]; | |
} | |
// Display all metrics in modern table format | |
foreach ($organizedMetrics as $i => $metricData) { | |
$metricName = htmlspecialchars($metricData['name']); | |
$scoreValue = htmlspecialchars($metricData['score']); | |
$levelDesc = getLevelDescription($metricData['score']); | |
$levelClass = getLevelClass($metricData['score']); | |
$html .= '<tr> | |
<td>' . $metricName . '</td> | |
<td>' . $scoreValue . '</td> | |
<td><span class="metric-level ' . $levelClass . '">' . $levelDesc . '</span></td> | |
</tr>'; | |
} | |
$html .= '</tbody> | |
</table> | |
<!-- Legend for the scoring system --> | |
<div class="metrics-legend"> | |
<div class="legend-item"> | |
<span class="legend-color" style="background-color: #ff3b30;"></span> | |
<span>Düşük (0-5.9)</span> | |
</div> | |
<div class="legend-item"> | |
<span class="legend-color" style="background-color: #ff9f0a;"></span> | |
<span>Orta (6-7.9)</span> | |
</div> | |
<div class="legend-item"> | |
<span class="legend-color" style="background-color: #34c759;"></span> | |
<span>Yüksek (8-10)</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2>Dijital Yaklaşım ve Tutum</h2> | |
<!-- Card layout for insights --> | |
<div class="insights-box"> | |
<div class="insights-heading">Teknoloji Eğilimi</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/^([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/m'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1</div>'], | |
nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
<h2>Karar Verme ve Problem Çözme</h2> | |
<!-- Card layout for decision making --> | |
<div class="insights-box"> | |
<div class="insights-heading">Problem Çözme Yaklaşımı</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/^([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/m'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1</div>'], | |
nl2br(htmlspecialchars($insights['decision_making'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2>İletişim ve Kişisel Eğilimler</h2> | |
<!-- Card layout for communication style --> | |
<div class="insights-box"> | |
<div class="insights-heading">İfade ve İletişim Biçimi</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/^([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/m'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1</div>'], | |
nl2br(htmlspecialchars($insights['communication_style'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
<!-- Strengths and development areas in a single card format --> | |
<h2>Güçlü Yönler ve Gelişim Alanları</h2> | |
<!-- Single card with sections --> | |
<div class="insights-box"> | |
<div class="insights-heading">Potansiyel ve Geliştirilebilir Alanlar</div> | |
<div class="insights-content"> | |
<!-- Strengths section --> | |
<div class="insights-section"> | |
<div class="insights-subheading" style="color: #34c759;">Güçlü Yönler</div> | |
' . | |
preg_replace( | |
['/Güçlü Yönler:(.*?)(?=Gelişime Açık Alanlar:|$)/s', '/\- (.*?)(?:\.|$)/'], | |
['$1', '<div class="insights-list-item">$1</div>'], | |
nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
<!-- Development areas section --> | |
<div class="insights-section"> | |
<div class="insights-subheading" style="color: #ff9f0a;">Gelişim Alanları</div> | |
' . | |
preg_replace( | |
['/.*?Gelişime Açık Alanlar:(.*?)$/s', '/\- (.*?)(?:\.|$)/'], | |
['$1', '<div class="insights-list-item">$1</div>'], | |
nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
</div> | |
<!-- Digital habits card --> | |
<h2>Dijital Alışkanlıklar</h2> | |
<div class="insights-box"> | |
<div class="insights-heading">Teknoloji Kullanım Rutinleri</div> | |
<div class="insights-content">' . | |
preg_replace( | |
['/\*\*(.*?)\*\*/', '/\- (.*?)(?:\.|$)/', '/^([A-ZÇĞİÖŞÜçğıöşü][^\.!?:]*?):/m'], | |
['<strong>$1</strong>', | |
'<div class="insights-list-item">$1</div>', | |
'<div class="insights-subheading">$1</div>'], | |
nl2br(htmlspecialchars($insights['digital_habits'] ?? 'Bilgi bulunamadı.')) | |
) . | |
'</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2><span style="display:inline-block; background-color:#0071e3; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">1</span> Zihin Haritası ve Yönetici Yetkinliği</h2> | |
<div class="insights-box" style="border-left: 4px solid #0071e3; background-color: rgba(0, 113, 227, 0.03);"> | |
<div class="insights-heading" style="color: #0071e3;">Stratejik Vizyon Derinliği</div> | |
<div class="insights-content"> | |
<p><strong>Uzun vadeli hedefleri nasıl kurgular, büyük resmi ne sıklıkla sorgular?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Öngörü yeteneği: Belirsizliklerde hangi sinyalleri besler, hangi göstergelere öncelik verir?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #34c759; background-color: rgba(52, 199, 89, 0.03);"> | |
<div class="insights-heading" style="color: #34c759;">Düşünce Hiyerarşisi ve Önceliklendirme</div> | |
<div class="insights-content"> | |
<p><strong>Karar maddelerini nasıl sıralar, risk/ödül dengesini neye göre tayin eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>"Azla çok yapma" becerisi: Minimal kaynak, maksimum etki yaklaşımı.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff9f0a; background-color: rgba(255, 159, 10, 0.03);"> | |
<div class="insights-heading" style="color: #ff9f0a;">Sistematik Analiz Süreçleri</div> | |
<div class="insights-content"> | |
<p><strong>Verileri ne kadar derinlemesine inceler? Hangi analitik araçları, kütüphaneleri veya zihinsel modelleri kullanır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Hipotez oluşturma ve test etme döngüsü: Kaç alternatif senaryo geliştirir, bunları nasıl sınar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #5856d6; background-color: rgba(88, 86, 214, 0.03);"> | |
<div class="insights-heading" style="color: #5856d6;">Liderlik ve Otorite Yaratma</div> | |
<div class="insights-content"> | |
<p><strong>Ekip içi inisiyatifi nasıl devreder? Kriz anında ne kadar "önden yürüme" eğilimindedir?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Güç dağılımı: Karar süreçlerine kimleri ve hangi seviyede dahil eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2><span style="display:inline-block; background-color:#34c759; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">2</span> Ego, Motivasyon ve Niyet Analizi</h2> | |
<div class="insights-box" style="border-left: 4px solid #ff3b30; background-color: rgba(255, 59, 48, 0.03);"> | |
<div class="insights-heading" style="color: #ff3b30;">Temel Ego Dinamikleri</div> | |
<div class="insights-content"> | |
<p><strong>Ego seviyesi: Geri bildirim alırken savunmacı mı, öğrenmeye açık mı davranır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Kendilik algısı: Başarıyı içsel mi yoksa dışsal faktörlere mi bağlar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff9500; background-color: rgba(255, 149, 0, 0.03);"> | |
<div class="insights-heading" style="color: #ff9500;">İçsel ve Dışsal Motivatörler</div> | |
<div class="insights-content"> | |
<p><strong>Hangi tür ödüller (statü, maddi, övgü, kişisel tatmin) kararlarını tetikler?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Zorluk ve konfor alanı dengesi: Ne zaman "güvende" kalmayı tercih eder, ne zaman sınırları zorlar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #30b0c7; background-color: rgba(48, 176, 199, 0.03);"> | |
<div class="insights-heading" style="color: #30b0c7;">Niyet Açıklığı ve Tutarlılık</div> | |
<div class="insights-content"> | |
<p><strong>Sözünde durma oranı: Verdiği sözler ne oranda ve nasıl gerçekle buluşur?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Amaçla davranış uyumu: Hedef açıklamaları ile günlük rutinleri arasındaki korelasyon.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['digital_habits'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #a2845e; background-color: rgba(162, 132, 94, 0.03);"> | |
<div class="insights-heading" style="color: #a2845e;">Risk, Gurur ve Kırılma Eşiği</div> | |
<div class="insights-content"> | |
<p><strong>Başarısızlık karşısında nasıl tepki verir? Hemen toparlanır mı yoksa uzun süre etkilenir mi?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Gurur kontrolü: Hata yaptığında bunu nasıl sahiplenir ve nasıl toparlar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2><span style="display:inline-block; background-color:#ff9f0a; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">3</span> Karar Verme ve Problem Çözme Mekanizması</h2> | |
<div class="insights-box" style="border-left: 4px solid #007aff; background-color: rgba(0, 122, 255, 0.03);"> | |
<div class="insights-heading" style="color: #007aff;">Karar Hızı vs. Doğruluk</div> | |
<div class="insights-content"> | |
<p><strong>Ani karar gereksinimlerinde ne kadar hızlı aksiyon alır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Derinlemesine analiz için ne kadar "zaman yatırımı" yapar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #5ac8fa; background-color: rgba(90, 200, 250, 0.03);"> | |
<div class="insights-heading" style="color: #5ac8fa;">Çözüm Yaratıcılığı ve Esneklik</div> | |
<div class="insights-content"> | |
<p><strong>Olası çözüm yollarının çeşitliliği: Ne kadar orijinal ve beklenmedik stratejiler üretir?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Plan B, C, D hazırlık seviyesi: Alternatif senaryolara ne ölçüde hazırlanır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #af52de; background-color: rgba(175, 82, 222, 0.03);"> | |
<div class="insights-heading" style="color: #af52de;">Veri Odaklı Karar Desteği</div> | |
<div class="insights-content"> | |
<p><strong>Sayısal verilere ne kadar güven duyar, sezgisel miyoklu davranır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Hangi metrikleri kritik KPI olarak takip eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff2d55; background-color: rgba(255, 45, 85, 0.03);"> | |
<div class="insights-heading" style="color: #ff2d55;">Stres Altında Karar Performansı</div> | |
<div class="insights-content"> | |
<p><strong>Basınç arttıkça odak ve yaratıcılığı yükselir mi yoksa daralır mı?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['decision_making'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>"Soğukkanlılık" göstergeleri: Panik düzeyini hangi noktalarda belli eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #4cd964; background-color: rgba(76, 217, 100, 0.03);"> | |
<div class="insights-heading" style="color: #4cd964;">Geri Besleme ve Sürekli İyileştirme</div> | |
<div class="insights-content"> | |
<p><strong>Karar sonrası değerlendirme: Ne kadar sık retrospektif yapar, dersleri nasıl kaydeder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['digital_habits'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2><span style="display:inline-block; background-color:#5856d6; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">4</span> İletişim Dili ve Sosyal İfade Tarzı</h2> | |
<div class="insights-box" style="border-left: 4px solid #64d2ff; background-color: rgba(100, 210, 255, 0.03);"> | |
<div class="insights-heading" style="color: #64d2ff;">Ses ve Üslup Profili</div> | |
<div class="insights-content"> | |
<p><strong>Yazılı/sözlü ton: Resmi-mi-informal aralığı, espri sıklığı, metafor kullanımı.</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['language_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Hangi anahtar kelimelerle "kendi dilini" yaratır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['language_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #00c7be; background-color: rgba(0, 199, 190, 0.03);"> | |
<div class="insights-heading" style="color: #00c7be;">Empati ve Etkileşim Yöntemi</div> | |
<div class="insights-content"> | |
<p><strong>Karşısındakinin duygularını algılama ve cevap verme hızı.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>İkna tırmanışı: Argümanı nasıl katman katman inşa eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff9f0a; background-color: rgba(255, 159, 10, 0.03);"> | |
<div class="insights-heading" style="color: #ff9f0a;">Açıklık ve Şeffaflık Düzeyi</div> | |
<div class="insights-content"> | |
<p><strong>Ne kadar bilgi paylaşır, hangi konularda sınır çizer?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Beklenmedik sorulara yanıt stratejisi: "Bilmiyorum" deme eğilimi.</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #5856d6; background-color: rgba(88, 86, 214, 0.03);"> | |
<div class="insights-heading" style="color: #5856d6;">Gösterge ve Beden Dili</div> | |
<div class="insights-content"> | |
<p><strong>Jest ve mimik tercihleri, ses tonu dalgalanmaları.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Uzaktan iletişimde (e-posta, mesaj) hangi imla, emoji veya formatları tercih eder?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="section"> | |
<h2><span style="display:inline-block; background-color:#ff3b30; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">5</span> Güçlü Yönler ve Potansiyel Alanlar</h2> | |
<div class="insights-box" style="border-left: 4px solid #34c759; background-color: rgba(52, 199, 89, 0.03);"> | |
<div class="insights-heading" style="color: #34c759;">Çekirdek Yetkinlikler (Core Strengths)</div> | |
<div class="insights-content"> | |
<p><strong>En yüksek performans gösterdiği üç temel beceri: Strateji, analitik, yaratıcılık vb.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Bu yetkinlikleri yıllar içinde nasıl geliştirdiğine dair örnek öyküler.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #ff3b30; background-color: rgba(255, 59, 48, 0.03);"> | |
<div class="insights-heading" style="color: #ff3b30;">Geliştirmeye Açık Alanların Derin Haritası</div> | |
<div class="insights-content"> | |
<p><strong>Hangi durumlarda verim kaybı yaşar, zorlandığı mental/kognitif engeller neler?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Bu alanları aşmak için geçmişte uyguladığı yöntemler ve başarı oranları.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['strengths_weaknesses'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #007aff; background-color: rgba(0, 122, 255, 0.03);"> | |
<div class="insights-heading" style="color: #007aff;">Uyum Yeteneği ve Öğrenme Kıvraklığı</div> | |
<div class="insights-content"> | |
<p><strong>Yeni bilgi edinme hızı: Karmaşık konuları ne kadar çabuk kavrar?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['technology_approach'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Geri bildirimlere adaptasyon: Öğrenilenleri davranışa ne ölçüde yansıtır?</strong></p> | |
<p>' . nl2br(htmlspecialchars($summary['character_analysis'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
<div class="insights-box" style="border-left: 4px solid #af52de; background-color: rgba(175, 82, 222, 0.03);"> | |
<div class="insights-heading" style="color: #af52de;">Tutku ve Uzmanlık Eğrisi</div> | |
<div class="insights-content"> | |
<p><strong>Hangi konularda derinlemesine "akademik" veya "pratik" bilgi sahibidir?</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['digital_habits'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
<p><strong>Uzmanlık alanlarında etki alanı: Makaleler, sunumlar, mentorluk hikâyeleri.</strong></p> | |
<p>' . nl2br(htmlspecialchars($insights['communication_style'] ?? 'Analiz bilgisi bulunamadı.')) . '</p> | |
</div> | |
</div> | |
</div> | |
<div class="page-break"></div> | |
<div class="footer"> | |
<p>Bu rapor POLARIS Dijital Yetenek Asistanı tarafından oluşturulmuştur.</p> | |
<p>© ' . date('Y') . ' iWise</p> | |
</div> | |
</body> | |
</html>'; | |
return $html; | |
} | |
/** | |
* Email Functions | |
*/ | |
/** | |
* Send email with attached report to the specified recipient | |
* | |
* @param string $recipientEmail Recipient email address | |
* @param string $recipientName Recipient name | |
* @param array $userData User information | |
* @param string $reportPath Path to the PDF report | |
* @return bool True if email was sent successfully | |
*/ | |
function sendReportEmail($recipientEmail, $recipientName, $userData, $reportPath) { | |
logMessage("Preparing to send email to: " . $recipientEmail); | |
// Configuration from config file | |
$config = getEmailConfig(); | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userFullName = $userName . ' ' . $userSurname; | |
try { | |
// Create new PHPMailer instance | |
$mail = new PHPMailer(true); | |
// Server settings | |
$mail->isSMTP(); | |
$mail->Host = $config['smtp_host']; | |
// Determine if we're using localhost | |
$isLocalhost = ($config['smtp_host'] === 'localhost' || $config['smtp_host'] === '127.0.0.1'); | |
// Configure SMTP authentication based on host | |
if ($isLocalhost) { | |
$mail->SMTPAuth = false; | |
$mail->SMTPSecure = false; | |
$mail->SMTPAutoTLS = false; | |
} else { | |
$mail->SMTPAuth = true; | |
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; | |
} | |
$mail->Username = $config['smtp_username']; | |
$mail->Password = $config['smtp_password']; | |
$mail->Port = $config['smtp_port']; | |
$mail->CharSet = 'UTF-8'; | |
// Increase timeout for slow SMTP servers | |
$mail->Timeout = 60; // 60 seconds | |
// SSL options for secure connection | |
if (!$isLocalhost) { | |
$mail->SMTPOptions = [ | |
'ssl' => [ | |
'verify_peer' => false, | |
'verify_peer_name' => false, | |
'allow_self_signed' => true | |
] | |
]; | |
} | |
// Enable SMTP debugging if in development mode | |
$mail->SMTPDebug = 0; // 0 = off, 2 = client/server messages | |
// Recipients | |
$mail->setFrom($config['from_email'], $config['from_name']); | |
$mail->addAddress($recipientEmail, $recipientName); | |
// Add CC recipients if provided in config | |
if (!empty($config['cc_emails'])) { | |
foreach ($config['cc_emails'] as $cc) { | |
$mail->addCC($cc); | |
} | |
} | |
// Add BCC recipients if provided in config | |
if (!empty($config['bcc_emails'])) { | |
foreach ($config['bcc_emails'] as $bcc) { | |
$mail->addBCC($bcc); | |
} | |
} | |
// Reply to | |
$mail->addReplyTo($config['reply_to_email'], $config['reply_to_name']); | |
// Attachments | |
if (file_exists($reportPath)) { | |
$mail->addAttachment($reportPath, 'POLARIS_Dijital_Yetenek_Raporu_' . $userFullName . '.pdf'); | |
} else { | |
throw new Exception("Rapor dosyası bulunamadı: $reportPath"); | |
} | |
// Content | |
$mail->isHTML(true); | |
$mail->Subject = 'POLARIS Dijital Yetenek Raporu - ' . $userFullName; | |
// Build email body | |
$mailBody = buildEmailHTML($userData, $config); | |
$mail->Body = $mailBody; | |
$mail->AltBody = strip_tags(str_replace('<br>', "\n", $mailBody)); | |
// Send email | |
$mail->send(); | |
logMessage("Email sent successfully to: " . $recipientEmail); | |
return true; | |
} catch (Exception $e) { | |
$error = "E-posta gönderilirken hata oluştu: " . $e->getMessage(); | |
logMessage("ERROR: " . $error); | |
// Try fallback method with PHP mail() function | |
try { | |
logMessage("Attempting fallback with mail() function"); | |
$headers = [ | |
'From' => $config['from_name'] . ' <' . $config['from_email'] . '>', | |
'Reply-To' => $config['reply_to_email'], | |
'MIME-Version' => '1.0', | |
'Content-Type' => 'text/html; charset=UTF-8' | |
]; | |
$mailBody = buildEmailHTML($userData, $config); | |
$subject = 'POLARIS Dijital Yetenek Raporu - ' . $userFullName; | |
$result = mail($recipientEmail, $subject, $mailBody, $headers); | |
if ($result) { | |
logMessage("Fallback email sent successfully with mail() function"); | |
return true; | |
} else { | |
throw new Exception("Fallback email sending with mail() function failed"); | |
} | |
} catch (Exception $fallbackError) { | |
logMessage("ERROR: Fallback email also failed: " . $fallbackError->getMessage()); | |
throw new Exception($error . "\n Fallback error: " . $fallbackError->getMessage()); | |
} | |
} | |
} | |
/** | |
* Get email configuration from config file | |
* | |
* @return array Email configuration | |
*/ | |
function getEmailConfig() { | |
// Check for app.php configuration first | |
$appConfigFile = __DIR__ . '/config/app.php'; | |
if (file_exists($appConfigFile)) { | |
$appConfig = require $appConfigFile; | |
if (isset($appConfig['email'])) { | |
// Convert app.php email config to expected format | |
$emailConfig = [ | |
'smtp_host' => $appConfig['email']['smtp_host'] ?? 'localhost', | |
'smtp_username' => $appConfig['email']['smtp_username'] ?? 'oguzhan.balim@eternadigital.com', | |
'smtp_password' => $appConfig['email']['smtp_password'] ?? '', | |
'smtp_port' => $appConfig['email']['smtp_port'] ?? 25, | |
'from_email' => $appConfig['email']['from_email'] ?? 'oguzhan.balim@eternadigital.com', | |
'from_name' => $appConfig['email']['from_name'] ?? 'iWise POLARIS', | |
'reply_to_email' => $appConfig['email']['from_email'] ?? 'oguzhan.balim@eternadigital.com', | |
'reply_to_name' => $appConfig['email']['from_name'] ?? 'iWise POLARIS', | |
'cc_emails' => isset($appConfig['email']['target_email']) ? [$appConfig['email']['target_email']] : [], | |
'bcc_emails' => [] | |
]; | |
logMessage("Using email configuration from app.php"); | |
return $emailConfig; | |
} | |
} | |
// Fall back to config.php if app.php doesn't have email settings | |
$configFile = __DIR__ . '/config/config.php'; | |
if (file_exists($configFile)) { | |
include $configFile; | |
if (isset($config['email'])) { | |
logMessage("Using email configuration from config.php"); | |
return $config['email']; | |
} | |
} | |
// Default configuration if no config files found | |
logMessage("No config files found, using default email configuration"); | |
return [ | |
'smtp_host' => 'localhost', | |
'smtp_username' => 'oguzhan.balim@eternadigital.com', | |
'smtp_password' => '', | |
'smtp_port' => 25, | |
'from_email' => 'oguzhan.balim@eternadigital.com', | |
'from_name' => 'iWise POLARIS', | |
'reply_to_email' => 'oguzhan.balim@eternadigital.com', | |
'reply_to_name' => 'iWise POLARIS', | |
'cc_emails' => [], | |
'bcc_emails' => [] | |
]; | |
} | |
/** | |
* Build HTML content for the email | |
* | |
* @param array $userData User information | |
* @param array $config Email configuration | |
* @return string HTML content for the email | |
*/ | |
function buildEmailHTML($userData, $config) { | |
// Get user information | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
$userFullName = $userName . ' ' . $userSurname; | |
// Build HTML email with Apple-inspired design | |
$html = ' | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header"> | |
<img class="logo" src="images/logo3.png" alt="iWise Logo"> | |
<h1>POLARIS Dijital Yetenek Raporu</h1> | |
</div> | |
<div class="content"> | |
<p>Sayın ' . htmlspecialchars($userFullName) . ',</p> | |
<p>POLARIS dijital yetenek değerlendirme süreciniz tamamlandı. Ekteki rapor, dijital yetkinlikleriniz ve teknolojiye yaklaşımınız hakkında detaylı bir analiz sunmaktadır.</p> | |
<div class="highlights"> | |
<div class="highlight-title">Rapor İçeriği</div> | |
<ul> | |
<li>Kişiselleştirilmiş dijital yaklaşım analizi</li> | |
<li>Dijital yetkinlik metrikleri</li> | |
<li>Güçlü yönler ve gelişim alanları</li> | |
<li>Teknoloji adaptasyonu değerlendirmesi</li> | |
<li>Karar verme ve iletişim tarzı analizi</li> | |
<li>Sohbet kaydı ve değerlendirme yanıtları</li> | |
</ul> | |
</div> | |
<p>Raporunuzu inceledikten sonra, dijital yetkinliklerinizi geliştirmeye yönelik adımlar hakkında daha fazla bilgi almak isterseniz, ekibimizle iletişime geçmekten çekinmeyin.</p> | |
<p>Dijital dönüşüm yolculuğunuzda başarılar dileriz.</p> | |
<p>Saygılarımızla,<br>iWise Ekibi</p> | |
</div> | |
<div class="footer"> | |
<p>Bu e-posta otomatik olarak oluşturulmuştur, lütfen yanıtlamayınız.</p> | |
<p>© ' . date('Y') . ' iWise. Tüm hakları saklıdır.</p> | |
</div> | |
</div> | |
</body> | |
</html>'; | |
return $html; | |
} | |
/** | |
* Main execution | |
*/ | |
// Check if the request is POST | |
if ($_SERVER['REQUEST_METHOD'] === 'POST') { | |
try { | |
// Get request body | |
$requestBody = file_get_contents('php://input'); | |
$data = json_decode($requestBody, true); | |
// Check if the request body is valid JSON | |
if ($data === null) { | |
throw new Exception("Geçersiz istek formatı: JSON verileri okunamadı."); | |
} | |
// Validate required fields | |
if (empty($data['userData']) || !is_array($data['userData'])) { | |
throw new Exception("Kullanıcı bilgileri eksik veya geçersiz format."); | |
} | |
// Get user information | |
$userData = $data['userData']; | |
$userId = $userData['id'] ?? null; | |
$userName = $userData['name'] ?? null; | |
if (!$userId) { | |
throw new Exception("Kullanıcı ID bulunamadı."); | |
} | |
if (!$userName) { | |
throw new Exception("Kullanıcı adı bulunamadı."); | |
} | |
logMessage("Processing request for user ID: {$userId}, name: {$userName}"); | |
// Find user chat data from database | |
$chatData = findUserChatData($userId); | |
if (!$chatData) { | |
// Try to create dummy conversation if no real data found | |
logMessage("No chat data found, creating dummy conversation"); | |
$messages = createDummyConversation($userData); | |
} else { | |
// Extract messages from chat data | |
$messages = extractMessages($chatData); | |
if (empty($messages)) { | |
$messages = createDummyConversation($userData); | |
} | |
} | |
// Find grading/assessment data from database | |
$gradingData = findGradingData($userId); | |
// Extract answers from grading data, or chat data as fallback | |
$answers = []; | |
if ($gradingData && isset($gradingData['answers'])) { | |
$answers = $gradingData['answers']; | |
logMessage("Using answers from grading data: " . count($answers)); | |
// Debug: Log first few answers to verify format | |
$i = 0; | |
foreach ($answers as $key => $value) { | |
logMessage("Answer {$i}: key=" . json_encode($key) . ", value=" . json_encode($value)); | |
if (++$i >= 3) break; // Only log first 3 for brevity | |
} | |
} elseif ($chatData && isset($chatData['answers'])) { | |
$answers = $chatData['answers']; | |
logMessage("Using answers from chat data: " . count($answers)); | |
// Debug: Log first few answers to verify format | |
$i = 0; | |
foreach ($answers as $key => $value) { | |
logMessage("Answer {$i}: key=" . json_encode($key) . ", value=" . json_encode($value)); | |
if (++$i >= 3) break; // Only log first 3 for brevity | |
} | |
} else { | |
// If no answers found, create default answers for testing | |
logMessage("WARNING: No answers found, creating default test answers"); | |
$answers = []; | |
for ($i = 0; $i < 20; $i++) { | |
$answers[$i] = rand(3, 7); // Random values between 3-7 | |
} | |
} | |
// Calculate metrics from assessment answers | |
$metrics = calculateMetrics($answers); | |
// Initialize variables | |
$summary = null; | |
$insights = null; | |
$reportPath = null; | |
$reportError = null; | |
// Try to generate conversation summary - continue even if it fails | |
try { | |
$summary = generateConversationSummary($messages, $userData, $metrics, $chatData); | |
logMessage("Successfully generated conversation summary"); | |
} catch (Exception $e) { | |
$errorMsg = "Failed to generate conversation summary: " . $e->getMessage(); | |
logMessage("ERROR: " . $errorMsg); | |
// Create a basic fallback summary | |
$summary = [ | |
'analysis' => "Conversation analysis could not be generated due to technical issues.", | |
'language_style' => "Language style analysis could not be generated.", | |
'character_analysis' => "Character analysis could not be generated." | |
]; | |
} | |
// Try to generate insights - continue even if it fails | |
try { | |
$insights = generateInsights($userData, $messages, $answers, $metrics, $chatData); | |
logMessage("Successfully generated insights"); | |
} catch (Exception $e) { | |
$errorMsg = "Failed to generate insights: " . $e->getMessage(); | |
logMessage("ERROR: " . $errorMsg); | |
// Create a basic fallback insights | |
$insights = [ | |
'strengths_weaknesses' => "Strengths and weaknesses analysis could not be generated due to technical issues.", | |
'technology_approach' => "Technology approach analysis could not be generated.", | |
'decision_making' => "Decision making analysis could not be generated.", | |
'communication_style' => "Communication style analysis could not be generated.", | |
'digital_habits' => "Digital habits analysis could not be generated." | |
]; | |
} | |
// Try to generate PDF report | |
try { | |
$reportPath = generatePDFReport($userData, $messages, $answers, $metrics, $summary, $insights); | |
logMessage("Successfully generated PDF report: " . $reportPath); | |
} catch (Exception $e) { | |
$reportError = "Failed to generate PDF report: " . $e->getMessage(); | |
logMessage("ERROR: " . $reportError); | |
throw new Exception($reportError); // Re-throw to be caught by outer try-catch | |
} | |
// Get recipient email from request or user data | |
$recipientEmail = $data['recipientEmail'] ?? ($userData['email'] ?? null); | |
// If no recipient email provided, check if email should be sent at all | |
$sendEmail = isset($data['sendEmail']) ? (bool)$data['sendEmail'] : true; | |
// Success response data | |
$response = [ | |
'success' => true, | |
'message' => 'Rapor başarıyla oluşturuldu.', | |
'report_path' => $reportPath, | |
'metrics' => $metrics | |
]; | |
// Send email if requested and email address is provided | |
if ($sendEmail && $recipientEmail) { | |
$recipientName = $userName . ' ' . ($userData['surname'] ?? ''); | |
$emailSent = sendReportEmail($recipientEmail, $recipientName, $userData, $reportPath); | |
$response['email_sent'] = $emailSent; | |
$response['recipient_email'] = $recipientEmail; | |
} else { | |
$response['email_sent'] = false; | |
$response['email_info'] = 'E-posta gönderimi talep edilmedi veya alıcı e-posta adresi belirtilmedi.'; | |
} | |
// Track execution time | |
$executionTime = microtime(true) - $startTime; | |
$response['execution_time'] = round($executionTime, 2) . ' seconds'; | |
logMessage("Request processed successfully in " . $response['execution_time']); | |
// Return success response | |
echo json_encode($response); | |
} catch (Exception $e) { | |
// Log error | |
logMessage("ERROR: " . $e->getMessage()); | |
// Return error response | |
http_response_code(500); | |
echo json_encode([ | |
'success' => false, | |
'error' => $e->getMessage() | |
]); | |
} | |
} else { | |
// Return method not allowed for non-POST requests | |
http_response_code(405); | |
echo json_encode([ | |
'success' => false, | |
'error' => 'Method Not Allowed' | |
]); | |
} | |
/** | |
* Function to get level class based on score | |
* | |
* @param float $score The score value | |
* @return string CSS class name for the level | |
*/ | |
function getLevelClass($score) { | |
if ($score >= 8) return 'level-high'; | |
if ($score >= 6) return 'level-medium'; | |
return 'level-low'; | |
} | |
/** | |
* Function to get level description based on score | |
* | |
* @param float $score The score value | |
* @return string Description of the level | |
*/ | |
function getLevelDescription($score) { | |
if ($score >= 8) return 'Yüksek'; | |
if ($score >= 6) return 'Orta'; | |
return 'Düşük'; | |
} | |
/** | |
* Convert emoji Unicode characters to styled text for PDF compatibility | |
* | |
* @param string $text Text that may contain emoji characters | |
* @return string Text with emoji characters replaced with styled text | |
*/ | |
function convertEmojiToTwemoji($text) { | |
// Map of common emojis to styled text replacements using ASCII symbols | |
$replacements = [ | |
'💬' => '<span style="color:#0071e3; font-weight:bold; padding:2px 5px;">[ ]</span>', | |
'🗣️' => '<span style="color:#34c759; font-weight:bold; padding:2px 5px;">(S)</span>', | |
'🧠' => '<span style="color:#ff9f0a; font-weight:bold; padding:2px 5px;">(B)</span>', | |
'❌' => '<span style="color:#ff3b30; font-weight:bold; padding:2px 5px;">(X)</span>', | |
'📊' => '<span style="color:#5856d6; font-weight:bold; padding:2px 5px;">(G)</span>', | |
'😊' => '<span style="color:#ff9500; font-weight:bold; padding:2px 5px;">:)</span>', | |
'👍' => '<span style="color:#34c759; font-weight:bold; padding:2px 5px;">(+)</span>', | |
'✅' => '<span style="color:#34c759; font-weight:bold; padding:2px 5px;">(✓)</span>', | |
'1️⃣' => '<span style="display:inline-block; background-color:#0071e3; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">1</span>', | |
'2️⃣' => '<span style="display:inline-block; background-color:#34c759; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">2</span>', | |
'3️⃣' => '<span style="display:inline-block; background-color:#ff9f0a; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">3</span>', | |
'4️⃣' => '<span style="display:inline-block; background-color:#5856d6; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">4</span>', | |
'5️⃣' => '<span style="display:inline-block; background-color:#ff3b30; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">5</span>' | |
]; | |
// Replace all emojis with their styled text equivalents | |
foreach ($replacements as $emoji => $replacement) { | |
$text = str_replace($emoji, $replacement, $text); | |
} | |
return $text; | |
} | |
/** | |
* Process messages for analysis, handling large conversations | |
* | |
* @param array $messages The extracted messages | |
* @param int $maxMessages Maximum number of messages to include (default 50) | |
* @return array Processed messages ready for analysis | |
*/ | |
function processMessagesForAnalysis($messages, $maxMessages = 50) { | |
$messageCount = count($messages); | |
logMessage("Processing {$messageCount} messages for analysis, max allowed: {$maxMessages}"); | |
// If message count is reasonable, return as is | |
if ($messageCount <= $maxMessages) { | |
logMessage("Message count within limit, processing all messages"); | |
return $messages; | |
} | |
// We have too many messages, need to truncate or summarize | |
logMessage("Large conversation detected ({$messageCount} messages), applying reduction strategy"); | |
// Check if there's already a summary indicator message | |
$hasSummaryMessage = false; | |
foreach ($messages as $msg) { | |
if (isset($msg['is_summary']) && $msg['is_summary'] === true) { | |
$hasSummaryMessage = true; | |
logMessage("Found pre-summarized message in the data"); | |
break; | |
} | |
} | |
// If messages were already summarized in chat.php, just return them as is | |
if ($hasSummaryMessage) { | |
logMessage("Using pre-summarized messages from chat.php"); | |
return $messages; | |
} | |
// Strategy 1: Keep first few and last set of messages | |
$firstMessages = array_slice($messages, 0, 10); // Keep first 10 messages | |
$lastMessages = array_slice($messages, -($maxMessages - 10)); // Keep remaining as last messages | |
// Add a system message indicating truncation | |
$truncationMessage = [ | |
'role' => 'system', | |
'content' => "Note: This conversation was truncated from {$messageCount} messages to {$maxMessages} messages due to size constraints. The first 10 and last " . ($maxMessages - 10) . " messages are shown.", | |
'timestamp' => time() * 1000, | |
'system_note' => true | |
]; | |
// Combine first messages, truncation note, and last messages | |
$processedMessages = array_merge($firstMessages, [$truncationMessage], $lastMessages); | |
logMessage("Successfully reduced message count to " . count($processedMessages)); | |
return $processedMessages; | |
} | |
/** | |
* Summarize chat content using OpenAI for very large conversations | |
* | |
* @param array $messages The messages to summarize | |
* @param array $userData User information for context | |
* @return string Summarized content | |
*/ | |
function summarizeChatContent($messages, $userData) { | |
logMessage("Summarizing chat content with " . count($messages) . " messages"); | |
// Extract user messages for context | |
$userMessages = array_filter($messages, function($msg) { | |
return isset($msg['role']) && $msg['role'] === 'user'; | |
}); | |
// Prepare data for summarization | |
$userName = $userData['name'] ?? 'Bilinmeyen'; | |
$userSurname = $userData['surname'] ?? 'Kullanıcı'; | |
// Create a condensed representation of the conversation | |
$condensedText = "Conversation with {$userName} {$userSurname} containing " . count($messages) . " messages.\n\n"; | |
$condensedText .= "Key user messages:\n"; | |
// Add a selection of representative user messages | |
$selectedUserMessages = array_slice($userMessages, 0, min(10, count($userMessages))); | |
foreach ($selectedUserMessages as $msg) { | |
$condensedText .= "- " . substr($msg['content'] ?? '', 0, 100) . (strlen($msg['content'] ?? '') > 100 ? "..." : "") . "\n"; | |
} | |
// Request summarization from OpenAI | |
$prompt = [ | |
[ | |
'role' => 'system', | |
'content' => "You are a helpful assistant that summarizes conversations. Analyze the following conversation data and provide a concise summary of the key points, user personality traits, and main topics discussed. Keep the summary under 500 words." | |
], | |
[ | |
'role' => 'user', | |
'content' => $condensedText | |
] | |
]; | |
try { | |
// Get API configuration | |
$apiKey = getApiKeyFromConfig(); | |
$appConfigFile = __DIR__ . '/config/app.php'; | |
$model = 'gpt-4.1'; // Default model | |
$endpointUrl = 'https://api.openai.com/v1/responses'; // Default endpoint | |
$maxTokens = 2000; // Reduced token count for summary | |
if (file_exists($appConfigFile)) { | |
$appConfig = require $appConfigFile; | |
if (isset($appConfig['openai'])) { | |
$model = $appConfig['openai']['model'] ?? $model; | |
$endpointUrl = $appConfig['openai']['endpoint_url'] ?? $endpointUrl; | |
logMessage("Using OpenAI model: {$model} for summarization"); | |
} | |
} | |
// Format request payload | |
$payload = [ | |
'model' => $model, | |
'input' => $prompt, | |
'text' => [ | |
'format' => ['type' => 'text'] | |
], | |
'reasoning' => (object)[], | |
'tools' => [], | |
'temperature' => 0.7, | |
'max_output_tokens' => $maxTokens, | |
'top_p' => 1, | |
'store' => true, | |
]; | |
// Send request to OpenAI | |
$ch = curl_init($endpointUrl); | |
curl_setopt_array($ch, [ | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_HTTPHEADER => [ | |
'Content-Type: application/json', | |
"Authorization: Bearer {$apiKey}" | |
], | |
CURLOPT_POST => true, | |
CURLOPT_POSTFIELDS => json_encode($payload), | |
CURLOPT_TIMEOUT => 60 // Shorter timeout for summary | |
]); | |
$response = curl_exec($ch); | |
if ($err = curl_error($ch)) { | |
curl_close($ch); | |
throw new RuntimeException("cURL error during summarization: {$err}"); | |
} | |
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
curl_close($ch); | |
if ($httpCode !== 200) { | |
throw new RuntimeException("API returned HTTP code {$httpCode} during summarization"); | |
} | |
// Parse response | |
$result = json_decode($response, true); | |
if (!$result) { | |
throw new RuntimeException("Failed to parse summarization API response"); | |
} | |
// Extract text from the output | |
$summary = ""; | |
if (isset($result['output']) && is_array($result['output'])) { | |
foreach ($result['output'] as $output) { | |
if (isset($output['type']) && $output['type'] === 'message' && | |
isset($output['content']) && is_array($output['content'])) { | |
foreach ($output['content'] as $content) { | |
if (isset($content['text'])) { | |
$summary = $content['text']; | |
break 2; | |
} | |
} | |
} | |
} | |
} | |
if (empty($summary)) { | |
logMessage("Warning: Empty summary received from OpenAI"); | |
return "Conversation summary could not be generated. The conversation contains " . count($messages) . " messages, discussing various topics."; | |
} | |
logMessage("Successfully generated conversation summary"); | |
return $summary; | |
} catch (Exception $e) { | |
logMessage("Failed to generate summary: " . $e->getMessage()); | |
return "Conversation summary could not be generated due to an error. The conversation contains " . count($messages) . " messages."; | |
} | |
} | |
/** | |
* Fix emoji display in HTML by replacing them with Font Awesome icons | |
* | |
* @param string $html The HTML content | |
* @return string The HTML with emojis replaced by Font Awesome icons | |
*/ | |
function fixEmojiInHTML($html) { | |
// Map of emojis to Font Awesome replacements | |
$emojiReplacements = [ | |
'💬 Konuşma Analizi' => '<i class="fa fa-comment" style="color:#0071e3; font-size:1.2em; margin-right:5px;"></i>Konuşma Analizi', | |
'🗣️ Dil ve Düşünce Tarzı' => '<i class="fa fa-user" style="color:#34c759; font-size:1.2em; margin-right:5px;"></i>Dil ve Düşünce Tarzı', | |
'🧠 Karakter Analizi' => '<i class="fa fa-brain" style="color:#ff9f0a; font-size:1.2em; margin-right:5px;"></i>Karakter Analizi', | |
'🧠 Dijital Yatkınlık Profili' => '<i class="fa fa-brain" style="color:#ff9f0a; font-size:1.2em; margin-right:5px;"></i>Dijital Yatkınlık Profili', | |
'1️⃣ Zihin Haritası ve Yönetici Yetkinliği' => '<span style="display:inline-block; background-color:#0071e3; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">1</span>Zihin Haritası ve Yönetici Yetkinliği', | |
'2️⃣ Ego, Motivasyon ve Niyet Analizi' => '<span style="display:inline-block; background-color:#34c759; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">2</span>Ego, Motivasyon ve Niyet Analizi', | |
'3️⃣ Karar Verme ve Problem Çözme Mekanizması' => '<span style="display:inline-block; background-color:#ff9f0a; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">3</span>Karar Verme ve Problem Çözme Mekanizması', | |
'4️⃣ İletişim Dili ve Sosyal İfade Tarzı' => '<span style="display:inline-block; background-color:#5856d6; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">4</span>İletişim Dili ve Sosyal İfade Tarzı', | |
'5️⃣ Güçlü Yönler ve Potansiyel Alanlar' => '<span style="display:inline-block; background-color:#ff3b30; color:white; width:1.5em; height:1.5em; text-align:center; line-height:1.5em; border-radius:50%; font-weight:bold; margin-right:5px;">5</span>Güçlü Yönler ve Potansiyel Alanlar', | |
'❌' => '<i class="fa fa-times-circle" style="color:#ff3b30; font-size:1.2em; margin-right:2px;"></i>' | |
]; | |
// Replace all instances of emojis with their Font Awesome equivalents | |
foreach ($emojiReplacements as $emoji => $replacement) { | |
$html = str_replace($emoji, $replacement, $html); | |
} | |
return $html; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment