Update Saqel Platform: 2026-08-28 18:08:03

This commit is contained in:
Hamza-Ayed
2026-08-28 18:08:03 +03:00
parent 597ef1809d
commit 6c8cb53af0
5 changed files with 135 additions and 12 deletions
@@ -46,17 +46,58 @@ class CurriculumController
];
file_put_contents($processingDir . '/' . $taskId . '.json', json_encode($taskState, JSON_UNESCAPED_UNICODE));
// Launch Background Worker
// Prepare task paths
$scriptPath = realpath(__DIR__ . '/../../scripts/curriculum_worker.php');
$logPath = $processingDir . '/' . $taskId . '.log';
$cmd = "php " . escapeshellarg($scriptPath) . " " . escapeshellarg($taskId) . " > " . escapeshellarg($logPath) . " 2>&1 &";
exec($cmd);
// Send processing response immediately
$response->json([
'status' => 'processing',
'task_id' => $taskId,
'message' => 'تم استلام الكتاب، وجاري المعالجة المعمقة بواسطة الذكاء الاصطناعي. يرجى الانتظار...'
]);
// Terminate request and flush buffers so the client receives the JSON immediately
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} else {
// Fallback for non-FPM
ob_end_flush();
flush();
}
// Run worker natively in the same PHP process (in the background from client's perspective)
try {
// Capture all output to log file
ini_set('display_errors', 1);
error_reporting(E_ALL);
ob_start();
// Execute the script logic natively by setting argv
$argv = ['curriculum_worker.php', $taskId];
$_SERVER['argv'] = $argv;
require $scriptPath;
$output = ob_get_clean();
file_put_contents($logPath, $output, FILE_APPEND);
} catch (\Exception $e) {
$err = "[Exception] " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine();
file_put_contents($logPath, $err . "
", FILE_APPEND);
// Update state file to error
$stateFile = $processingDir . '/' . $taskId . '.json';
if (file_exists($stateFile)) {
$st = json_decode(file_get_contents($stateFile), true);
$st['status'] = 'error';
$st['message'] = 'تعطل النظام أثناء التحليل (Crash). يرجى مراجعة سجل الأخطاء.';
file_put_contents($stateFile, json_encode($st, JSON_UNESCAPED_UNICODE));
}
}
// Ensure script stops here so it doesn't return anything else
exit;
}
/**
@@ -82,9 +123,34 @@ class CurriculumController
$response->json($state);
}
/**
* Get Upload Log
*/
public function getUploadLog(Request $request, Response $response): void
{
$taskId = $request->getQueryParams()['task_id'] ?? '';
if (empty($taskId)) {
$response->status(400)->json(['status' => 'error', 'message' => 'رقم المهمة مفقود']);
return;
}
$processingDir = __DIR__ . '/../../storage/curriculum/processing';
$logFile = $processingDir . '/' . $taskId . '.log';
if (!file_exists($logFile)) {
$response->status(404)->json(['status' => 'error', 'message' => 'سجل الأخطاء غير موجود']);
return;
}
$logContent = file_get_contents($logFile);
$response->json(['status' => 'success', 'log' => $logContent]);
}
/**
* Get Complete Live Tree
*/
public function getTree(Request $request, Response $response): void
{
$response->json([
+35
View File
@@ -450,8 +450,43 @@ class CurriculumStudio
</div>
<p id="upload_progress_text" style="color: var(--text-secondary); font-size: 13px; font-weight: bold;">جاري التهيئة...</p>
<p id="upload_progress_percent" style="color: var(--accent-gold); font-size: 12px; margin-top: 5px;">0%</p>
<button id="btn_view_logs" type="button" style="margin-top: 15px; background: transparent; border: 1px solid var(--border-color); color: var(--text-muted); padding: 5px 12px; border-radius: 6px; font-size: 11px; cursor: pointer; transition: all 0.2s;" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='var(--text-muted)'" onclick="toggleUploadLogs()">🔍 عرض سجل السيرفر (Logs)</button>
<div id="upload_logs_container" style="display: none; margin-top: 15px; width: 100%; text-align: left;">
<textarea id="upload_logs_textarea" readonly style="width: 100%; height: 120px; background: #000; color: #0f0; font-family: monospace; font-size: 11px; border: 1px solid #333; border-radius: 4px; padding: 8px; resize: none; direction: ltr;"></textarea>
</div>
</div>
</div>
<script>
let currentUploadTaskId = null;
function toggleUploadLogs() {
const container = document.getElementById('upload_logs_container');
if (container.style.display === 'none') {
container.style.display = 'block';
fetchUploadLogs();
} else {
container.style.display = 'none';
}
}
async function fetchUploadLogs() {
if (!currentUploadTaskId) return;
try {
const res = await fetch(`/api/curriculum/upload-log?task_id=${currentUploadTaskId}`);
const data = await res.json();
const textarea = document.getElementById('upload_logs_textarea');
if (data.status === 'success') {
textarea.value = data.log || 'No logs generated yet...';
textarea.scrollTop = textarea.scrollHeight;
}
} catch (e) {
console.error(e);
}
}
</script>
<style>
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }