ingestِ دوباره جایگزین نمیکرد: qdrant_point_id یک uuid4 تازه به ازای هر ردیف
است، پس خواندنِ دوبارهی یک صفحه نسخهی تکراری کنارِ نسخهی قدیمی میگذاشت و
جستجو نمیتوانست تشخیص بدهد کدام کدام است.
--refresh {figures,unjudgeable,both,all} و --refresh-pages اضافه شدند.
سه تصمیمِ طراحی که عمدیاند:
۱. پاکسازی صفحهبهصفحه است و درست پیش از خواندنِ همان صفحه، نه یکجا از اول.
وسطِ تست یک crash همین را ثابت کرد: فقط یک صفحه خالی ماند (۲۷۹→۲۷۶) و بقیهی
کتاب دستنخورده. پاکسازیِ یکجا همان crash را به ۸۱ صفحهی خالی تبدیل میکرد.
۲. اول Qdrant، بعد دیتابیس. شناسهی نقطه فقط در ردیفِ DB است، پس ترتیبِ برعکس
یعنی شکستِ Qdrant نقاط را برای همیشه بیصاحب میگذارد — نه قابلِ یافتن، نه
قابلِ پاک کردن.
۳. order از Max گرفته میشود نه count: بازخوانی ردیفها را از وسط پاک میکند و
count عددی میداد که با orderهای موجود تصادم داشت.
تخمینِ هزینه حالا از اندازهگیریِ واقعیِ پنلِ صورتحساب میآید نه از جدولِ قیمت،
و وعدهی «با Batch API نصف» حذف شد چون GapGPT اصلاً /v1/batches ندارد.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
97 lines
6.1 KiB
Markdown
97 lines
6.1 KiB
Markdown
# کتابهای درسی (PDF)
|
||
|
||
فایلهای PDF کتابهای درسی را در همین پوشه بگذارید. خودِ PDFها در گیت
|
||
ذخیره نمیشوند (حجمشان زیاد است) — فقط همین فایل راهنما ردیابی میشود.
|
||
|
||
## منبع
|
||
|
||
نسخهی رسمی و بهروزِ کتابها: <https://irtextbook.ir>
|
||
(از خارج ایران در دسترس نیست؛ دانلود باید از داخل ایران انجام شود.)
|
||
|
||
## اولویت (بهروزشده ۱۴۰۵/۰۶/۲۱)
|
||
|
||
سینیور اولویت را عوض کرد: **از پایه ششم به بالا**، با تمرکز روی پایههای
|
||
ترانزیشنی ۶، ۷، ۹ و ۱۰. کتابهای ابتدایی (اول/دوم/چهارم/پنجم) که قبلاً
|
||
دانلود شدهاند فعلاً در نوبت نیستند.
|
||
|
||
| پایه | وضعیت |
|
||
|---|---|
|
||
| سوم، ششم، هفتم | روی Qdrant هست (ساختهی تیم دیگر) — PDF نداریم جز هفتم |
|
||
| هشتم، نهم، دهم | ingest شده؛ بازخوانیِ صفحههای شکلدار مانده |
|
||
| یازدهم، دوازدهم | در نوبتِ ingest (۱۴۰۵/۰۶/۲۸) |
|
||
| اول، دوم، چهارم، پنجم | PDF موجود است، خارج از اولویتِ فعلی |
|
||
|
||
⚠️ کتابِ ریاضیِ یازدهم و دوازدهم چند رشته دارد (تجربی، ریاضیفیزیک، انسانی).
|
||
نامِ فایل و `Textbook.grade` باید رشته را مشخص کند، وگرنه دو کتابِ متفاوت
|
||
سرِ یک collection دعوا میکنند.
|
||
|
||
## نامگذاری
|
||
|
||
نامِ فایل باید دقیقاً با `filename` در `rag/services/textbooks.py` یکی باشد،
|
||
مثلاً `ریاضی نهم.pdf`.
|
||
|
||
## چطور ingest کنیم
|
||
|
||
```bash
|
||
# اول ببینید چه چیزی قرار است پردازش شود (رایگان، هیچ فراخوانیِ مدلی ندارد)
|
||
python manage.py rag_ingest_book --grade نهم --plan
|
||
|
||
# یک فصل، با سقفِ صفحه برای کنترلِ هزینه
|
||
python manage.py rag_ingest_book --grade نهم --chapters 1 --max-pages 5
|
||
|
||
# کلِ کتاب (از جایی که مانده ادامه میدهد)
|
||
python manage.py rag_ingest_book --grade نهم
|
||
```
|
||
|
||
هر اجرا صفحههایی را که قبلاً chunk ساختهاند رد میکند، پس قطع کردنش با
|
||
Ctrl-C بیخطر است و اجرای دوباره هزینهی رفته را دوباره نمیپردازد.
|
||
|
||
## بازخوانیِ صفحههای معیوب
|
||
|
||
کتابهایی که پیش از افزوده شدنِ قاعدهی «self-contained» به پرامپت ingest
|
||
شدهاند، مسئلههایی دارند که به «شکلِ زیر» یا «جدولِ روبهرو» ارجاع میدهند
|
||
بیآنکه محتوای آن شکل در متن آمده باشد. مدل آن شکل را **دیده بود**؛ فقط از او
|
||
خواسته نشده بود بنویسدش. پس با خواندنِ دوبارهی همان صفحهها جبران میشود.
|
||
|
||
```bash
|
||
# اول ببینید چند صفحه و چه هزینهای — رایگان، هیچ فراخوانیِ مدلی ندارد
|
||
python manage.py rag_ingest_book --grade نهم --refresh both --plan
|
||
|
||
# فقط صفحههای ارجاعدهنده به شکل/جدول
|
||
python manage.py rag_ingest_book --grade نهم --refresh figures
|
||
|
||
# صفحههای مشخص (وقتی خودتان فهرست دارید)
|
||
python manage.py rag_ingest_book --grade نهم --refresh-pages 18,44,60-65
|
||
```
|
||
|
||
سه نکته که باید بدانید:
|
||
|
||
- **بازخوانی پاک میکند.** واحدِ کار «صفحه» است نه chunk، چون vision یک صفحه را
|
||
یکجا میخواند. پس chunkهای سالمِ همان صفحه هم دور ریخته و از نو ساخته
|
||
میشوند و `solution_verdict`شان پاک میشود. فرمان پیش از خرج کردن نشان
|
||
میدهد چند تای آنها رأیِ «agrees» داشتهاند و تأیید میگیرد (`--yes` رد میکند).
|
||
- **بعدش `rag_verify_solutions` را دوباره اجرا کنید،** وگرنه chunkهای تازه
|
||
بیرأی میمانند و تولیدِ سؤال — که فقط `agrees` میخواند — نادیدهشان میگیرد.
|
||
- **پاکسازی صفحهبهصفحه است،** درست پیش از خواندنِ همان صفحه. پس قطعِ وسطِ کار
|
||
(Ctrl-C، تمام شدنِ اعتبار) فقط یک صفحه را خالی میگذارد، نه کلِ کتاب را.
|
||
|
||
## افزودنِ کتابِ جدید
|
||
|
||
در `rag/services/textbooks.py` یک `Textbook` بسازید با:
|
||
|
||
- `page_offset` — اختلافِ شمارهی صفحهی چاپشده با شمارهی صفحه در PDF
|
||
(جلد و فهرست جلوترند). از روی فهرستِ کتاب و بازبینیِ یک صفحهی مرزی درمیآید.
|
||
- `chapters` — بازهی صفحهی هر فصل بر اساسِ شمارهی چاپشده. بازهها باید
|
||
پشتِهم و بدونِ حفره باشند (تستِ `TextbookLayoutTests` همین را چک میکند).
|
||
- `grade_label` — همان رشتهای که در payloadِ `grade` مینشیند.
|
||
|
||
عنوانِ فصلها خودکار در `known_collections.MATH_CHAPTERS` ثبت میشود، پس
|
||
جستجو بلافاصله میتواند شمارهی فصل را به رشتهی دقیق تبدیل کند.
|
||
|
||
## بعدش چه اتفاقی میافتد
|
||
|
||
هر صفحه به تصویر تبدیل میشود، مدل vision انواع مسئله را استخراج میکند
|
||
(`type` / `keywords` / `generalSolution` / `problem` / `solution`)، نتیجه هم در
|
||
جدول `rag.LessonChunk` (منبع حقیقت، پیش خودمان) ذخیره میشود و هم بهصورت
|
||
نقطه در Qdrant ایندکس میشود — با همان قرارداد payloadی که تیم دیگر دارد.
|