File size: 25,063 Bytes
51d43b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666d78c
 
 
 
 
 
51d43b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666d78c
51d43b8
 
 
 
 
 
 
 
666d78c
51d43b8
666d78c
51d43b8
666d78c
51d43b8
 
666d78c
 
 
 
 
51d43b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
"""
draft_builder.py — منشئ المسودات وملف المادة الخام + الملخص التحليلي
النسخة v3.0

التغييرات:
  - Analytical Brief: ملخص تحليلي هيكلي قبل المادة الخام مباشرة
  - Object-level truncation: الاقتطاع على مستوى كائن الراوي كاملاً
  - تعطيك الأولوية للنتائج التي فيها qattan_evidence
  - إضافة volume في العرض (بيانات التوثيق الكاملة)
  - _render_narrator_block: دالة مساعدة قابلة للاختبار
"""


class PromptBuilder:
    def __init__(self, term: str, category: str, draft: dict):
        self.term = term
        self.category = category
        defaults = {
            "term": term,
            "category": category,
            "total_results": 0,
            "by_section": {},
        }
        self.draft = {**defaults, **draft}

    def _group_by_narrator(self, results: list[dict]) -> dict[str, list[dict]]:
        grouped = {}
        for r in results:
            narrator = r.get("narrator", "").strip() or "أقوال عامة ونصوص متفرقة"
            if narrator not in grouped:
                grouped[narrator] = []
            grouped[narrator].append(r)
        return grouped

    def _sort_items_by_quality(self, items: list[dict]) -> list[dict]:
        """
        ترتيب النتائج: أولاً ما فيه دليل نسبة القطان، ثم الباقي.
        """
        with_evidence = [r for r in items if r.get("qattan_evidence")]
        without_evidence = [r for r in items if not r.get("qattan_evidence")]
        return with_evidence + without_evidence

    def _render_narrator_block(
        self,
        narrator: str,
        items: list[dict],
        max_items: int = 50,
        max_chars_per_item: int = 800,
    ) -> str:
        """
        تصيير كتلة راوٍ واحد — دالة مساعدة معزولة قابلة للاختبار.
        تشمل: اسم الكتاب، المؤلف، الجزء، الصفحة، الرابط، السياق، النص.
        """
        lines = []

        if narrator == "أقوال عامة ونصوص متفرقة":
            lines.append(f"#### 📌 نصوص متفرقة وعامة ({len(items)} نتيجة)")
        else:
            lines.append(f"#### 👤 الراوي: {narrator} ({len(items)} قول)")
        lines.append("")

        # ترتيب بالجودة: دليل القطان أولاً
        sorted_items = self._sort_items_by_quality(items)

        for item in sorted_items[:max_items]:
            book = item.get("book", "")
            author = item.get("author", "")
            volume = item.get("volume", "")
            page = item.get("page", "")
            text = item.get("text", "")
            link = item.get("link", "")
            context = item.get("context", "")
            qattan_evidence = item.get("qattan_evidence", "")
            is_negated = item.get("is_negated", False)

            # رأس المصدر مع بيانات الجزء والصفحة
            vol_page = ""
            if volume:
                vol_page += f" ج:{volume}"
            if page:
                vol_page += f" ص:{page}"

            lines.append(f"##### 📖 {book}{author}{vol_page}")

            if link:
                lines.append(f"- **المصدر**: 🔗 {link}")

            meta = []
            if is_negated:
                meta.append("⚠️ صيغة نفي")
            if qattan_evidence:
                meta.append(f"✅ دليل النسبة: «{qattan_evidence}»")
            if meta:
                lines.append(f"- **ملاحظات**: " + " | ".join(meta))

            if context:
                lines.append(f"- **السياق**: ...{context.strip()[:400]}...")

            if text:
                lines.append("")
                truncated = text[:max_chars_per_item]
                lines.append("  > " + truncated.replace("\n", "\n  > "))

            lines.append("")

        return "\n".join(lines)

    def build_section_draft(
        self, section_key: str, max_chars: int | None = None
    ) -> str:
        """
        بناء مسودة مبحث واحد مع Object-level truncation.

        الجديد في v2.0:
          - الاقتطاع يحترم حدود كائن الراوي (لا قطع في المنتصف)
          - النتائج ذات دليل القطان تُضاف أولاً قبل الحد
          - تحذير عند تجاوز الحد مع إحصاء ما تُرك
        """
        if max_chars is None:
            max_chars = {
                "tahdid": 5_000,
                "lugha": 8_000,
                "tarikh": 8_000,
                "madloul": 15_000,  # زيادة لاستيعاب الرواة الكثيرين
                "muqarana": 12_000,
                "khatima": 4_000,
                "masadir": 8_000,
            }.get(section_key, 8_000)

        key_to_sec = {
            "lugha": 1,
            "tarikh": 2,
            "madloul": 3,
            "muqarana": 4,
            "khatima": 5,
        }

        lines = []

        if section_key == "tahdid":
            lines.append(f"### ملخص إحصائي لبيانات اللفظ «{self.term}»")
            lines.append(f"- **إجمالي النتائج**: {self.draft.get('total_results', 0)}")
            lines.append(f"- **المصادر والمصنفات**: {self.draft.get('books_count', 0)}")
            lines.append(f"- **الأئمة والنقاد**: {self.draft.get('authors_count', 0)}")
            narrators = self.draft.get("narrators", [])
            if narrators:
                lines.append(f"- **الرواة المترجمون** ({len(narrators)} راوٍ):")
                for n in narrators[:30]:
                    lines.append(f"  * {n['name']} — المصدر: {n['book']}")
            return "\n".join(lines)

        elif section_key == "masadir":
            lines.append(f"### المصادر المعتمدة في دراسة «{self.term}»")
            seen_books = {}
            by_section = self.draft.get("by_section", {})
            for sec_data in by_section.values():
                for item in sec_data.get("results", []):
                    book = item.get("book", "")
                    author = item.get("author", "")
                    link = item.get("link", "")
                    volume = item.get("volume", "")
                    if book:
                        key = (book, author)
                        if key not in seen_books:
                            seen_books[key] = link

            for (book, author), link in sorted(seen_books.items()):
                link_str = f" 🔗 {link}" if link else ""
                lines.append(f"- *{book}{author}.{link_str}")
            if len(seen_books) > 100:
                lines.append(
                    f"\n> ⚠️ **تنبيه**: عدد المصادر كبير ({len(seen_books)} كتاباً). "
                    f"اكتفِ بأهمها في القائمة مع ملاحظة أن الحصر الكامل في draft.md."
                )
            return "\n".join(lines)

        elif section_key in key_to_sec:
            sec_num = key_to_sec[section_key]
            by_section = self.draft.get("by_section", {})
            sec_data = by_section.get(sec_num) or by_section.get(str(sec_num))
            if not sec_data:
                return "لا توجد نتائج خاصة بهذا المبحث في المادة الخام."

            lines.append(
                f"### نتائج المبحث: {sec_data.get('name', '')} ({sec_data.get('count', 0)} نتيجة)"
            )
            if sec_data.get("description"):
                lines.append(f"*{sec_data['description']}*")
            lines.append("")

            results = sec_data.get("results", [])
            grouped_results = self._group_by_narrator(results)

            sorted_narrators = sorted(
                grouped_results.keys(),
                key=lambda x: (x == "أقوال عامة ونصوص متفرقة", x),
            )

            # ── Object-level truncation ──────────────────────────────────
            current_size = 0
            skipped_narrators = 0

            for narrator in sorted_narrators:
                items = grouped_results[narrator]

                # تصيير كتلة الراوي كاملاً أولاً
                block = self._render_narrator_block(narrator, items)
                block_size = len(block)

                if current_size + block_size > max_chars:
                    if current_size == 0:
                        # الراوي الأول أكبر من الحد → خذ ما يسع
                        lines.append(block[:max_chars])
                        current_size = max_chars
                    else:
                        skipped_narrators += 1
                    continue

                lines.append(block)
                lines.append("---")
                lines.append("")
                current_size += block_size

            if skipped_narrators > 0:
                lines.append(
                    f"\n> ⚠️ **تنبيه**: تم حذف {skipped_narrators} راوٍ إضافي "
                    f"لتجاوز حد المساحة ({max_chars:,} حرف). "
                    f"راجع ملف draft.md الكامل للاطلاع على جميع النتائج."
                )

            return "\n".join(lines)

        return ""

    def build_analytical_brief(self) -> str:
        """
        بناء ملخص تحليلي هيكلي — يُقدَّم للنموذج قبل المادة الخام
        ليعرف بالضبط ماذا يكتب وما الدليل المتاح لكل قسم.
        """
        by_section = self.draft.get("by_section", {})
        total = self.draft.get("total_results", 0)
        narrators = self.draft.get("narrators", [])

        lines = []
        lines.append(f"# الملخص التحليلي — لفظ «{self.term}»")
        lines.append(f"- التصنيف: {'تعديل' if self.category == 'tadeel' else 'جرح'}")
        lines.append(f"- إجمالي النتائج: {total}")
        lines.append(f"- عدد الرواة: {len(narrators)}")
        lines.append("")

        # Per-section breakdown
        lines.append("## توزيع المادة الخام على الأقسام:")
        lines.append("| القسم | عدد النتائج | النتائج مع دليل القطان | ملاحظات |")
        lines.append("|-------|-----------|----------------------|---------|")

        section_key_map = {
            1: ("lugha", "المبحث الأول: الدراسة اللغوية"),
            2: ("tarikh", "المبحث الثاني: الدراسة الاصطلاحية"),
            3: ("madloul", "المبحث الثالث: استعمال القطان"),
            4: ("muqarana", "المبحث الرابع: الدراسة التطبيقية المقارنة"),
            5: ("khatima", "المبحث الخامس: الخاتمة"),
        }

        for sec_num, sec_data in by_section.items():
            key_int = int(sec_num) if isinstance(sec_num, str) else sec_num
            results = sec_data.get("results", [])
            with_evidence = sum(1 for r in results if r.get("qattan_evidence"))
            sec_name = sec_data.get("name", f"قسم {key_int}")

            # Determine quality flag
            if with_evidence > 0:
                flag = f"✓ {with_evidence} نتيجة مع دليل القطان"
            elif len(results) == 0:
                flag = "✗ لا توجد نتائج — يحتاج بحثاً إضافياً"
            else:
                flag = "⚠ نتائج عامة بدون دليل نسبة صريح"

            lines.append(f"| {sec_name} | {len(results)} | {with_evidence} | {flag} |")

        lines.append("")

        # Narrator summary
        if narrators:
            lines.append("## أبرز الرواة المذكورين:")
            for n in narrators[:15]:
                name = n.get("name", "")
                book = n.get("book", "")
                lines.append(f"- {name} (المصدر: {book})")
            if len(narrators) > 15:
                lines.append(f"- ... و{len(narrators) - 15} راوٍ إضافياً")
            lines.append("")

        # Key instructions
        lines.append("## تعليمات للنموذج:")
        lines.append(
            "- استخدم كل التوثيقات الموجودة في المادة الخام — لا تترك أي نتيجة دون استخدام"
        )
        lines.append("- كل فقرة يجب أن تحتوي توثيقاً مباشراً واحداً على الأقل")
        lines.append(
            "- إذا كان القسم ضعيفاً في المادة الخام، اكتب ما تراه ثم اختم بـ (يحتاج توثيقاً)"
        )
        lines.append("- لا تكرر نفس التوثيق أكثر من مرتين متتاليتين")
        lines.append("- استخدم الصيغة: (المؤلف (ت وفاة)، الكتاب، ج، ص، 🔗 الرابط)")

        return "\n".join(lines)

    def build_markdown_draft(self) -> str:
        """بناء ملف المسودة الكاملة — للحفظ كمرجع، لا للـ AI مباشرة"""
        lines = []
        lines.append(f"# {self.term} — ملف المادة الخام (Research Dossier)")
        lines.append("")
        lines.append(f"**التصنيف**: {'تعديل' if self.category == 'tadeel' else 'جرح'}")
        lines.append(f"**إجمالي النتائج**: {self.draft.get('total_results', 0)}")
        lines.append(f"**المصادر**: {self.draft.get('books_count', 0)}")
        lines.append(f"**المؤلفون**: {self.draft.get('authors_count', 0)}")
        lines.append("")
        lines.append("---")
        lines.append("")

        by_section = self.draft.get("by_section", {})
        for sec_num in sorted(by_section.keys()):
            sec_data = by_section[sec_num]
            lines.append(
                f"## {sec_data.get('name', '')} ({sec_data.get('count', 0)} نتيجة)"
            )
            if sec_data.get("description"):
                lines.append(f"*{sec_data['description']}*")
            lines.append("")

            results = sec_data.get("results", [])
            grouped_results = self._group_by_narrator(results)

            sorted_narrators = sorted(
                grouped_results.keys(),
                key=lambda x: (x == "أقوال عامة ونصوص متفرقة", x),
            )

            for narrator in sorted_narrators:
                items = grouped_results[narrator]
                block = self._render_narrator_block(
                    narrator, items, max_items=150, max_chars_per_item=1500
                )
                lines.append(block)
                lines.append("---")
                lines.append("")

        return "\n".join(lines)

    def build_ai_prompt(self) -> str:
        md_draft = self.build_markdown_draft()

        prompt = f"""# مهمة: كتابة دراسة أكاديمية شاملة للفظ «{self.term}»

أنت باحث رسالة ماجستير تكتب في «ألفاظ الجرح والتعديل عند يحيى بن سعيد القطان (ت 198 هـ)». عليك كتابة دراسة شاملة ومفصلة تشمل كل الأقوال والروايات المتعلقة باللفظ.

## طريقة التعامل مع المادة
- لا تجعل كثرة النتائج دليلاً على ثبوت النسبة.
- لا تدخل في مبحث استعمال القطان إلا النتائج التي فيها «دليل النسبة إلى القطان».
- النتائج الموسومة بـ «يحتاج مراجعة يدوية» تذكر في ملاحظات البحث فقط، ولا تبني عليها حكماً.
- إن لم تثبت نسبة اللفظ إلى القطان من المادة الخام فصرح بذلك ولا تؤلف دراسة موهمة.

## المواد الخام من البحث — استخدمها كلها ولا تترك أي نتيجة

{{md_draft[:25000]}}

## التعليمات الإلزامية — التزم بها حرفياً

### القواعد الذهبية — مقدسة غير قابلة للانتهاك
1. **لا تخترع روابط** — استخدم فقط الروابط الموجودة في المواد الخام
2. **لا تكتب فقرة بغير مصدر** — كل فقرة = توثيق واحد على الأقل
3. **لا تخترع أحاديث أو أقوالاً** — استخدم فقط ما وجدته في المواد الخام
4. **إذا لم تجد رابطاً** اكتب: (يحتاج توثيقاً)
5. **استخدم كل البيانات** — لا تترك أي نتيجة دون استخدام

### صيغة التوثيق — إلزامية داخل المتن
استخدم التوثيق المباشر بين قوسين داخل الفقرة، لا تستخدم الحواشي المرقمة:
`(المؤلف الكامل (ت وفاة هـ)، *اسم الكتاب كاملاً*، ج:_، ص:_، تحقيق: المحقق، الناشر، الطبعة، السنة، 🔗 https://shamela.ws/book/XXXX/YYYY)`

إذا كانت المادة الخام لا تحتوي بيانات التحقيق أو الناشر فاكتب المتاح ثم أضف: `(يحتاج استكمال بيانات النشر)`.

### هيكل الدراسة — أقسام مفصلة

```
1. تمهيد قصير
2. المبحث الأول: الدراسة اللغوية
3. المبحث الثاني: الدراسة الاصطلاحية
4. المبحث الثالث: استعمال القطان
5. المبحث الرابع: الدراسة التطبيقية المقارنة
6. المبحث الخامس: الخلاصة والنتائج
7. قائمة المصادر
```

### أسلوب الكتابة — مباشر وشامل ومفصل
- اكتب فقرات طويلة ومفصلة — لا تكتب فقرات قصيرة
- استخدم كل الأقوال والروايات الموجودة في المواد الخام
- اذكر كل راوٍ وصف باللفظ مع القول الكامل
- استخدم عبارة «يبدو أن» و«لا يزال» عند الغموض
- انقل النصوص بنصها بالعربية الأصلية
- لا تكرر نفس المعنى بكلمات مختلفة
- استخدم عبارة «إذا تقرر هذا» عند الانتقال بين الأفكار
- اختم بـ«والله أعلم»

### القواعد النحوية والأسلوبية
- لا تستخدم علامات تعجب أو أسئلة كثيرة
- اكتب بلغة أكاديمية محايدة
- لا تستخدم «نحن» — استخدم «يُلاحَظ» أو «يتبين»

### ممنوعات
- ممنوع استخدام الجداول نهائياً في المستند (يُعرض الحصر في صورة فقرات وقوائم مرقمة منسابة)
- اذكر حصر وتفصيل كافة الرواة في البداية فوراً بعد التمهيد وقبل المبحث الأول
- ممنوع أي كلمة إنجليزية
- ممنوع ذكر «الذكاء الاصطناعي» أو «AI»
- التمييز بين: يحيى بن سعيد القطان (ت 198 هـ) ≠ ابن القطان الفاسي (ت 628 هـ)

اكتب الدراسة كاملة الآن — من التمهيد إلى قائمة المصادر — دون توقف. ابدأ بـ:

**تمهيد**

عند تتبع أقوال يحيى بن سعيد القطان في الرواة..."""

        return prompt

    def build_external_super_prompt(self) -> str:
        md_draft = self.build_markdown_draft()

        # Load global instructions
        from config import SYSTEM_PROMPTS_DIR

        global_path = SYSTEM_PROMPTS_DIR / "00_global_rules.md"
        global_rules = ""
        if global_path.exists():
            global_rules = global_path.read_text(encoding="utf-8")

        # Load section rules
        from modules.study_writer import SYSTEM_PROMPTS, SECTIONS

        sections_rules = []
        for key, name in SECTIONS:
            filename = SYSTEM_PROMPTS.get(key, "")
            if filename:
                sec_path = SYSTEM_PROMPTS_DIR / filename
                if sec_path.exists():
                    try:
                        raw_rules = sec_path.read_text(encoding="utf-8")
                        sec_rules = raw_rules.replace("{term}", self.term)
                        sections_rules.append(
                            f"### قواعد كتابة قسم: {name} ({key})\n{sec_rules}\n"
                        )
                    except Exception:
                        sec_rules = sec_path.read_text(encoding="utf-8")
                        sections_rules.append(
                            f"### قواعد كتابة قسم: {name} ({key})\n{sec_rules}\n"
                        )

        sections_rules_str = "\n\n".join(sections_rules)

        # Build prompt using safe replacement/concatenation to avoid f-string brace parsing errors
        term_category_label = "تعديل" if self.category == "tadeel" else "جرح"
        header = (
            "# البرومبت الخارق للكتابة اليدوية عبر AI خارجي (مثل Claude أو ChatGPT)\n"
            "هذا الملف مخصص لمساعدتك في كتابة الدراسة يدوياً عبر أي نموذج ذكاء اصطناعي تفضله في حال حدوث ضغط على خوادم OpenRouter أو رغبتك في استخدام نموذج محدد مثل Claude 3.5 Sonnet أو GPT-4o.\n\n"
            "## تعليمات الاستخدام:\n"
            "1. انسخ محتوى هذا الملف بالكامل.\n"
            "2. ألصقه في نافذة محادثة جديدة مع الذكاء الاصطناعي.\n"
            "3. انتظر حتى يقوم الذكاء الاصطناعي بتوليد الدراسة الأكاديمية كاملة (من التمهيد إلى قائمة المصادر).\n"
            '4. انسخ النص الناتج من الذكاء الاصطناعي، ثم ألصقه في قسم "الاستيراد اليدوي" في الواجهة الرسومية لتوليد ملف الورد بالتنسيق الاحترافي والهوامش الفنية والتدقيق المنهجي.\n\n'
            "---\n\n"
            "# [البرومبت المقترح للنسخ]\n\n"
            "أنت باحث أكاديمي متميز تكتب في رسالة الماجستير للباحث (أحمد مرزوق) تحت إشراف الأستاذ الدكتور (أحمد معبد عبد الكريم)، وموضوعك هو: «ألفاظ الجرح والتعديل عند يحيى بن سعيد القطان (ت 198 هـ)».\n\n"
            f"مطلوب منك كتابة دراسة أكاديمية شاملة ومفصلة للفظ: «{self.term}» (تصنيفه: {term_category_label})، وذلك بناءً على المادة الخام المرفقة وقواعد الصياغة والتوثيق الأكاديمية الصارمة المدرجة أدناه.\n\n"
            "---\n\n"
            "## أولاً: القواعد الأكاديمية والصياغة المنهجية (هام جداً)\n"
        )

        middle = "\n\n---\n\n## ثانياً: قواعد كتابة مباحث الدراسة بالتفصيل\n"

        draft_section = (
            "\n\n---\n\n"
            "## ثالثاً: المادة الخام الكاملة للبحث (استخرج منها كافة التوثيقات والأسماء والروابط)\n"
        )

        footer = (
            "\n\n---\n\n"
            "## رابعاً: أمر البدء بالكتابة\n"
            "اكتب الدراسة الآن كاملة (من التمهيد إلى قائمة المصادر) كملف واحد متصل متناسق، مستخدماً كل النقول والأدلة والروابط الواردة في المادة الخام أعلاه دون اختصار أو إهمال لأي راوٍ أو نتيجة.\n"
            "تنبيه حاسم: اكتب المحتوى النهائي مباشرة باللغة العربية الفصحى. ممنوع منعاً باتاً التفكير بصوت عالٍ أو كتابة أي مسودات أو تعليقات باللغة الإنجليزية. ابدأ الآن بـ:\n\n"
            "**التمهيد**\n"
        )

        full_prompt = (
            header
            + global_rules
            + middle
            + sections_rules_str
            + draft_section
            + md_draft
            + footer
        )
        return full_prompt