update ai

This commit is contained in:
Flatlogic Bot 2026-04-14 06:44:14 +00:00
parent 614ba05f47
commit 6ae92a7546
6 changed files with 312 additions and 15 deletions

View File

@ -21,7 +21,8 @@ if (empty($title)) {
try {
$systemPrompt = "أنت مساعد ذكاء اصطناعي متخصص في كتابة أوصاف مهنية وجذابة وملهمة لأنشطة وفعاليات اللجان في المؤسسات والجمعيات الخيرية. " .
"قم بكتابة وصف موجز (حوالي 2-3 أسطر) للنشاط التالي بناءً على عنوانه. " .
"اجعل الوصف احترافياً، باللغة العربية الفصحى، ولا تضف أي مقدمات أو خواتيم (مثل 'إليك الوصف' أو 'هذا هو'). ابدأ بالوصف مباشرة.";
"اجعل الوصف احترافياً، باللغة العربية الفصحى، ولا تضف أي مقدمات أو خواتيم (مثل 'إليك الوصف' أو 'هذا هو'). ابدأ بالوصف مباشرة. " .
"تأكد من صياغة الوصف بأسلوب مختلف ومبتكر في كل مرة. (مفتاح عشوائي لضمان التغيير: " . uniqid() . ")";
$response = LocalAIApi::createResponse([
'model' => 'gpt-4o-mini',
@ -40,13 +41,24 @@ try {
echo json_encode(['success' => true, 'description' => trim($text)]);
} else {
// Fallback dummy text to avoid blocking the user while Flatlogic support fixes the AI Proxy
// Fallback dummy text arrays to ensure variety while AI proxy is down
error_log("AI Error Generate Activity: " . print_r($response, true));
$dummyText = "هذا وصف تجريبي تم إنشاؤه لأن خادم الذكاء الاصطناعي الخاص بالمنصة غير متاح حالياً. نشاط «{$title}» يهدف إلى تعزيز المشاركة المجتمعية وتقديم قيمة مضافة للفئة المستهدفة من خلال تنظيم فعاليات مبتكرة ومهنية.";
$fallbackTemplates = [
"نشاط «{$title}» يهدف إلى تعزيز المشاركة المجتمعية وتقديم قيمة مضافة للفئة المستهدفة من خلال تنظيم فعاليات مبتكرة ومهنية.",
"نسعى من خلال «{$title}» إلى إحداث أثر إيجابي ملموس، وتطوير مهارات وقدرات المشاركين بأسلوب تفاعلي وجذاب يحقق الأهداف المرجوة.",
"يمثل نشاط «{$title}» مبادرة نوعية تسعى لتوثيق الروابط بين أفراد المجتمع، وتقديم برامج هادفة تلبي احتياجاتهم وتطلعاتهم برؤية عصرية.",
"من خلال إطلاق «{$title}»، نطمح لتوفير بيئة ملهمة ومحفزة تدعم الإبداع، وتسهم بشكل مباشر في تحقيق رسالة اللجنة وأهدافها الاستراتيجية.",
"يهدف مشروع «{$title}» إلى تمكين المستفيدين وتوسيع آفاقهم عبر حزمة من الفعاليات المتخصصة التي تتميز بالجودة والتنظيم الاحترافي."
];
// Pick a random template
$dummyText = $fallbackTemplates[array_rand($fallbackTemplates)];
echo json_encode(['success' => true, 'description' => $dummyText, 'is_mock' => true]);
}
} catch (Exception $e) {
error_log("Generate Activity Error: " . $e->getMessage());
echo json_encode(['success' => false, 'error' => "حدث خطأ داخلي. يرجى المحاولة لاحقاً."]);
}
}

View File

@ -0,0 +1,64 @@
<?php
// api/generate_plan_details.php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../ai/LocalAIApi.php';
session_start();
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'error' => 'يرجى تسجيل الدخول أولاً']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$title = trim($input['title'] ?? '');
if (empty($title)) {
echo json_encode(['success' => false, 'error' => 'يرجى إدخال عنوان الخطة أولاً']);
exit;
}
try {
$systemPrompt = "أنت مساعد ذكاء اصطناعي متخصص في كتابة أوصاف مهنية وجذابة وملهمة لخطط وأهداف الجمعيات الخيرية ومؤشرات الأداء (KPIs). " .
"قم بكتابة وصف موجز (حوالي 2-3 أسطر) للخطة أو الهدف التالي بناءً على عنوانه. " .
"اجعل الوصف احترافياً، باللغة العربية الفصحى، ولا تضف أي مقدمات أو خواتيم (مثل 'إليك الوصف' أو 'هذا هو'). ابدأ بالوصف مباشرة. " .
"تأكد من صياغة الوصف بأسلوب مختلف ومبتكر في كل مرة. (مفتاح عشوائي لضمان التغيير: " . uniqid() . ")";
$response = LocalAIApi::createResponse([
'model' => 'gpt-4o-mini',
'input' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => "عنوان الخطة/الهدف: " . $title],
]
]);
if (!empty($response['success'])) {
$text = LocalAIApi::extractText($response);
if ($text === '') {
$decoded = LocalAIApi::decodeJsonFromResponse($response);
$text = $decoded ? json_encode($decoded, JSON_UNESCAPED_UNICODE) : (string)($response['data'] ?? '');
}
echo json_encode(['success' => true, 'description' => trim($text)]);
} else {
// Fallback dummy text arrays to ensure variety while AI proxy is down
error_log("AI Error Generate Plan: " . print_r($response, true));
$fallbackTemplates = [
"خطة «{$title}» تهدف إلى تحقيق أثر مستدام وتلبية تطلعات الفئة المستهدفة من خلال تنفيذ مبادرات استراتيجية مدروسة وفق أعلى معايير الجودة.",
"تأتي «{$title}» ضمن استراتيجيتنا الشاملة لتعزيز كفاءة الأداء، وضمان تقديم خدمات نوعية تتوافق مع الرؤية المستقبلية للمؤسسة وأهدافها.",
"من خلال مؤشر الأداء «{$title}»، نركز على قياس وتطوير العمليات التشغيلية لضمان الاستدامة وتحقيق أعلى درجات التميز المؤسسي الممكنة.",
"نسعى لتطبيق أهداف «{$title}» بخطوات عملية ومؤشرات واضحة تضمن الاستغلال الأمثل للموارد، وتعظيم الأثر الاجتماعي والإنساني لبرامجنا.",
"تمثل «{$title}» خارطة طريق طموحة لرفع كفاءة العمل الخيري، وتفعيل الشراكات الفاعلة بما ينعكس إيجاباً على مجمل مخرجات الجمعية واستدامتها."
];
// Pick a random template
$dummyText = $fallbackTemplates[array_rand($fallbackTemplates)];
echo json_encode(['success' => true, 'description' => $dummyText, 'is_mock' => true]);
}
} catch (Exception $e) {
error_log("Generate Plan Error: " . $e->getMessage());
echo json_encode(['success' => false, 'error' => "حدث خطأ داخلي. يرجى المحاولة لاحقاً."]);
}

View File

@ -231,11 +231,16 @@ $status_labels = [
<div class="mb-3">
<label class="form-label">العنوان</label>
<input type="text" class="form-control" name="title" value="<?= htmlspecialchars($plan['title'] ?? '') ?>" required>
<input type="text" class="form-control" name="title" id="title_edit_<?= $plan['id'] ?>" value="<?= htmlspecialchars($plan['title'] ?? '') ?>" required>
</div>
<div class="mb-3">
<label class="form-label">الوصف</label>
<textarea class="form-control" name="description" rows="2"><?= htmlspecialchars($plan['description'] ?? '') ?></textarea>
<div class="d-flex justify-content-between align-items-center mb-1">
<label class="form-label fw-bold mb-0">الوصف</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="btn_desc_edit_<?= $plan['id'] ?>" onclick="generatePlanDesc('edit', <?= $plan['id'] ?>)">
<i class="fas fa-magic"></i> توليد الوصف بـ AI
</button>
</div>
<textarea class="form-control" name="description" id="desc_edit_<?= $plan['id'] ?>" rows="2"><?= htmlspecialchars($plan['description'] ?? '') ?></textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
@ -325,11 +330,16 @@ $status_labels = [
<div class="mb-3">
<label class="form-label">العنوان</label>
<input type="text" class="form-control" name="title" required placeholder="مثال: كفالة 100 يتيم خلال العام">
<input type="text" class="form-control" name="title" id="title_add" required placeholder="مثال: كفالة 100 يتيم خلال العام">
</div>
<div class="mb-3">
<label class="form-label">الوصف</label>
<textarea class="form-control" name="description" rows="2"></textarea>
<div class="d-flex justify-content-between align-items-center mb-1">
<label class="form-label fw-bold mb-0">الوصف</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="btn_desc_add" onclick="generatePlanDesc('add', null)">
<i class="fas fa-magic"></i> توليد الوصف بـ AI
</button>
</div>
<textarea class="form-control" name="description" id="desc_add" rows="2"></textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
@ -371,4 +381,51 @@ $status_labels = [
</div>
</div>
<!-- AI Generation Script -->
<script>
async function generatePlanDesc(type, id) {
const titleInputId = type === 'add' ? 'title_add' : 'title_edit_' + id;
const descFieldId = type === 'add' ? 'desc_add' : 'desc_edit_' + id;
const btnId = type === 'add' ? 'btn_desc_add' : 'btn_desc_edit_' + id;
const titleInput = document.getElementById(titleInputId);
const title = titleInput.value.trim();
if (!title) {
alert("يرجى إدخال عنوان الخطة أولاً لتوليد الوصف.");
titleInput.focus();
return;
}
const btn = document.getElementById(btnId);
const descField = document.getElementById(descFieldId);
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> جاري التوليد...';
btn.disabled = true;
try {
const response = await fetch("api/generate_plan_details.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: title })
});
const data = await response.json();
if (data.success) {
descField.value = data.description;
} else {
alert(data.error || "حدث خطأ أثناء توليد الوصف.");
}
} catch (error) {
console.error("Error:", error);
alert("حدث خطأ في الاتصال بالخادم.");
} finally {
btn.innerHTML = originalText;
btn.disabled = false;
}
}
</script>
<?php require_once 'includes/footer.php'; ?>

View File

@ -96,6 +96,9 @@ usort($committees, function($a, $b) {
<a href="print_committees_report.php" target="_blank" class="btn btn-outline-primary btn-sm me-2">
<i class="fas fa-print me-1"></i> طباعة تقرير اللجان والأعضاء
</a>
<a href="print_activities_report.php" target="_blank" class="btn btn-outline-info btn-sm me-2">
<i class="fas fa-print me-1"></i> طباعة تقرير الأنشطة
</a>
<a href="committees.php" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-arrow-right me-1"></i> عودة لإدارة اللجان
</a>

156
print_activities_report.php Normal file
View File

@ -0,0 +1,156 @@
<?php
session_start();
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/includes/permissions.php';
require_once __DIR__ . '/includes/settings.php';
if (!isLoggedIn() || !canView('committees')) {
exit("لا توجد صلاحية للوصول لهذه الصفحة.");
}
$settings = get_settings();
$db = db();
$committee_id = $_GET['committee_id'] ?? null;
// Build query for activities
$query = "
SELECT
a.id, a.title, a.description, a.activity_date, a.location,
c.name as committee_name
FROM committee_activities a
JOIN committees c ON a.committee_id = c.id
";
$params = [];
if (!isAdmin()) {
// Only activities from committees the user is a member of
$query .= "
JOIN committee_members m ON c.id = m.committee_id
JOIN charity_members cm ON m.charity_member_id = cm.id
JOIN users u ON (u.id = cm.user_id) OR (cm.email != '' AND cm.email = u.email) OR (cm.name = u.full_name) OR (cm.name = u.username)
WHERE u.id = ?
";
$params[] = $_SESSION['user_id'];
if ($committee_id) {
$query .= " AND c.id = ?";
$params[] = $committee_id;
}
} else {
if ($committee_id) {
$query .= " WHERE c.id = ?";
$params[] = $committee_id;
}
}
$query .= " ORDER BY a.activity_date DESC, c.name ASC";
$stmt = $db->prepare($query);
$stmt->execute($params);
$activities = $stmt->fetchAll(PDO::FETCH_ASSOC);
$report_title = "تقرير الأنشطة والفعاليات";
if ($committee_id) {
$stmt_c = $db->prepare("SELECT name FROM committees WHERE id = ?");
$stmt_c->execute([$committee_id]);
$committee_name = $stmt_c->fetchColumn();
if ($committee_name) {
$report_title .= " - لجنة " . htmlspecialchars($committee_name);
}
}
?>
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($report_title) ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css" rel="stylesheet">
<style>
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap');
body { font-family: 'Tajawal', sans-serif; background-color: #fff; color: #000; }
.print-header { border-bottom: 2px solid #333; padding-bottom: 20px; margin-bottom: 30px; display: flex; justify-content: space-between; align-items: center; }
.print-logo { max-height: 80px; }
table { width: 100%; margin-top: 15px; margin-bottom: 15px; border-collapse: collapse; }
th, td { border: 1px solid #dee2e6; padding: 12px 8px; text-align: right; vertical-align: top; }
th { background-color: #f1f3f5; font-weight: bold; }
.badge-date { background-color: #e9ecef; border: 1px solid #ccc; padding: 4px 8px; border-radius: 4px; font-size: 0.9em; white-space: nowrap; }
@media print {
body { margin: 0; padding: 0; }
.btn-print { display: none !important; }
@page { margin: 1cm; }
}
</style>
</head>
<body>
<div class="container py-4">
<!-- Print Button -->
<div class="text-start mb-4 btn-print">
<button onclick="window.print()" class="btn btn-primary"><i class="fas fa-print me-2"></i> طباعة التقرير</button>
<button onclick="window.close()" class="btn btn-secondary">إغلاق</button>
</div>
<!-- Header -->
<div class="print-header">
<div>
<h2 class="mb-1 fw-bold"><?= htmlspecialchars($settings['site_name'] ?? '') ?></h2>
<p class="mb-0 text-muted fs-5"><?= $report_title ?></p>
<small>تاريخ التقرير: <?= date('Y-m-d') ?></small>
</div>
<div>
<?php if (!empty($settings['site_logo'])): ?>
<img src="<?= htmlspecialchars($settings['site_logo'] ?? '') ?>" class="print-logo" alt="Logo">
<?php endif; ?>
</div>
</div>
<h3 class="text-center text-decoration-underline mb-4 fw-bold">سجل الأنشطة والفعاليات المنجزة</h3>
<?php if (empty($activities)): ?>
<div class="alert alert-info text-center">لا توجد أنشطة مسجلة في هذا التقرير.</div>
<?php else: ?>
<table>
<thead>
<tr>
<th style="width: 50px; text-align: center;">م</th>
<?php if (!$committee_id): ?>
<th style="width: 150px;">اللجنة</th>
<?php endif; ?>
<th style="width: 250px;">اسم النشاط</th>
<th>الوصف والتفاصيل</th>
<th style="width: 120px;">التاريخ</th>
<th style="width: 150px;">الموقع</th>
</tr>
</thead>
<tbody>
<?php foreach ($activities as $index => $a): ?>
<tr>
<td style="text-align: center;"><?= $index + 1 ?></td>
<?php if (!$committee_id): ?>
<td><strong><?= htmlspecialchars($a['committee_name'] ?? '') ?></strong></td>
<?php endif; ?>
<td class="fw-bold" style="color: #0d6efd;"><?= htmlspecialchars($a['title'] ?? '') ?></td>
<td><?= nl2br(htmlspecialchars($a['description'] ?? '')) ?: '<span class="text-muted fst-italic">لا يوجد وصف</span>' ?></td>
<td><span class="badge-date"><i class="far fa-calendar-alt me-1"></i> <?= htmlspecialchars($a['activity_date'] ?? '') ?></span></td>
<td><?= htmlspecialchars($a['location'] ?? '') ?: '<span class="text-muted">-</span>' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<!-- Footer -->
<div class="mt-5 pt-3 border-top text-center text-muted small">
هذا التقرير معتمد ومستخرج آلياً من نظام الإدارة - <?= htmlspecialchars($settings['site_name'] ?? '') ?>
</div>
</div>
<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
// window.onload = function() { window.print(); }
</script>
</body>
</html>

View File

@ -494,11 +494,16 @@ if ($tab === 'members') {
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h5 class="mb-0">أنشطة وفعاليات اللجنة</h5>
<?php if (canAdd('committees')): ?>
<button class="btn btn-sm btn-primary" onclick="openActivityModal('add')">
<i class="fas fa-plus"></i> إضافة نشاط
</button>
<?php endif; ?>
<div>
<a href="print_activities_report.php?committee_id=<?= $id ?>" target="_blank" class="btn btn-sm btn-outline-info me-2">
<i class="fas fa-print"></i> طباعة الأنشطة
</a>
<?php if (canAdd('committees')): ?>
<button class="btn btn-sm btn-primary" onclick="openActivityModal('add')">
<i class="fas fa-plus"></i> إضافة نشاط
</button>
<?php endif; ?>
</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">