From 6f95620397e31fe37f15bbd5ca4d8e48706955df Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Sat, 21 Feb 2026 11:04:51 +0330 Subject: [PATCH] Add documentation for collection naming strategy and incremental vector synchronization. Implement background task for syncing data from PostgreSQL to Qdrant, ensuring zero duplicate embeddings and crash resilience. Update API routes to trigger synchronization process. --- docs/COLLECTION_NAMING.md | 120 +++++++++++++++++++ docs/INCREMENTAL_VECTOR_SYNC.md | 204 ++++++++++++++++++++++++++++++++ docs/index.md | 7 ++ out.md | 20 +++- src/api/routes.py | 26 ++-- src/knowledge/sync_rag.py | 108 +++++++++++++++++ src/utils/collection_name.py | 67 +++++++++++ 7 files changed, 536 insertions(+), 16 deletions(-) create mode 100644 docs/COLLECTION_NAMING.md create mode 100644 docs/INCREMENTAL_VECTOR_SYNC.md create mode 100644 docs/index.md create mode 100644 src/knowledge/sync_rag.py create mode 100644 src/utils/collection_name.py diff --git a/docs/COLLECTION_NAMING.md b/docs/COLLECTION_NAMING.md new file mode 100644 index 0000000..73880e0 --- /dev/null +++ b/docs/COLLECTION_NAMING.md @@ -0,0 +1,120 @@ +# Collection Naming Strategy + +## Why This Module Exists + +When working with vector databases like Qdrant, **the name of your collection is not cosmetic — it is a data integrity contract.** Mixing incompatible vectors in the same collection silently corrupts your search results with no error or warning. + +This module (`collection_name.py`) generates deterministic, self-documenting collection names that encode every critical parameter. If any parameter changes, a new name is produced, which means a new collection — preventing data corruption automatically. + +--- + +## The Golden Rule of Vector Collections + +> **You MUST create a new collection whenever the mathematical comparison between two vectors becomes invalid.** + +If you compare a vector from **Model A** with a vector from **Model B**, the result is **meaningless garbage**. The numbers look real, cosine similarity returns a value, but it means nothing. There is no error. There is no crash. Your app just silently returns wrong answers. + +Therefore, incompatible vectors **cannot live in the same collection.** + +--- + +## The 4 Factors That Force a New Collection + +| # | Factor | Why It Forces a New Collection | Priority | +|---|--------|-------------------------------|----------| +| 1 | **Model** | `jina-v3` vectors are numerically unrelated to `openai-v3` vectors. They live in completely different mathematical spaces. | :red_circle: Critical | +| 2 | **Dimensions** | You cannot insert a 1024-dim vector into a collection built for 768-dim. Qdrant will reject it outright. | :red_circle: Critical | +| 3 | **Distance Metric** | A collection using `Cosine` ranks results differently than one using `Dot Product`. Mixing them invalidates your ranking logic. | :orange_circle: High | +| 4 | **Chunking Strategy** | If Batch A was chunked by paragraphs and Batch B by sentences, search results become biased and inconsistent. Apples vs. oranges. | :yellow_circle: Medium | + +--- + +## Naming Format + +``` +[PROJECT]_[MODEL]_[DIMENSIONS]d_[CHUNK_SIZE]t_[TYPE] +``` + +### Example Breakdown + +``` +imam_reza_jina-v3_1024d_512t_hybrid +│ │ │ │ │ +│ │ │ │ └── hybrid = sparse + dense vectors enabled +│ │ │ └── 512t = 512 tokens per chunk +│ │ └── 1024d = vector dimensionality +│ └── jina-v3 = embedding model +└── imam_reza = project / domain name +``` + +| Segment | Purpose | +|---------|---------| +| `imam_reza` | **Project/Domain** — keeps this data isolated from other apps or datasets. | +| `jina-v3` | **Model** — the embedding brain. Changing models = new collection, always. | +| `1024d` | **Dimensions** — tells you (and Qdrant) the vector size at a glance. | +| `512t` | **Chunk size** — "512 tokens per chunk". If you later experiment with 128-token chunks, a separate collection lets you compare performance fairly. | +| `hybrid` | **Search type** — indicates sparse vectors are enabled alongside dense vectors. | + +--- + +## How It Works + +`get_collection_name()` pulls values from two sources: + +1. **`config/embeddings.yaml`** — the active embedding model, its `id`, and `dimensions`. +2. **Environment variables** (`.env`) — `BASE_COLLECTION_NAME`, `EMBEDDER_DIMENSIONS`, `CHUNK_SIZE`, `IS_HYBRID`. + +Every parameter can also be overridden explicitly via function arguments. + +### Resolution Priority (per parameter) + +| Parameter | 1st (highest) | 2nd | 3rd (fallback) | +|-----------|---------------|-----|-----------------| +| `project_name` | Explicit arg | `BASE_COLLECTION_NAME` env var | `"default_project"` | +| `model_name` | Explicit arg | `embeddings.yaml` → `default` key | — | +| `dimensions` | Explicit arg | `embeddings.yaml` → model config | `EMBEDDER_DIMENSIONS` env var | +| `chunk_size` | Explicit arg | `CHUNK_SIZE` env var | `500` | +| `is_hybrid` | Explicit arg | `IS_HYBRID` env var | `true` | + +### Model Lookup + +The `model_name` parameter is flexible — it accepts either: +- A **config key** from `embeddings.yaml` (e.g., `"jina_AI"`) +- A **model id** (e.g., `"jina-embeddings-v4"`) + +--- + +## Usage + +```python +from src.utils.collection_name import get_collection_name + +# All defaults from config + env +name = get_collection_name() +# → "dovodi_collection_jina-embeddings-v4_1024d_500t_hybrid" + +# Override chunk size +name = get_collection_name(chunk_size=128) +# → "dovodi_collection_jina-embeddings-v4_1024d_128t_hybrid" + +# Dense-only collection +name = get_collection_name(is_hybrid=False) +# → "dovodi_collection_jina-embeddings-v4_1024d_500t_dense" + +# Different model from embeddings.yaml +name = get_collection_name(model_name="openai_small") +# → "dovodi_collection_text-embedding-3-small_1536d_500t_hybrid" +``` + +--- + +## What Happens If You Don't Do This + +| Scenario | What Goes Wrong | +|----------|----------------| +| You switch from `jina-v3` to `openai-v3` but keep the same collection | Old jina vectors and new openai vectors get compared. Search returns nonsense. **No error is raised.** | +| You change dimensions from 1024 to 768 | Qdrant crashes on insert — dimension mismatch. At least this one is loud. | +| You change chunk size from 512 to 128 | Short chunks get unfairly boosted in similarity scores against long chunks. Search quality degrades silently. | +| You switch from Cosine to Dot Product | Ranking logic is inverted for unnormalized vectors. Top results become bottom results. | + +The naming convention makes these mistakes **structurally impossible** — if any parameter changes, a new collection name is generated, and the old data is never touched. diff --git a/docs/INCREMENTAL_VECTOR_SYNC.md b/docs/INCREMENTAL_VECTOR_SYNC.md new file mode 100644 index 0000000..5ede7ac --- /dev/null +++ b/docs/INCREMENTAL_VECTOR_SYNC.md @@ -0,0 +1,204 @@ +# Incremental Vector Synchronization + +**PostgreSQL → Qdrant | Database-Driven Incremental Embedding Pipeline** + +--- + +## Overview + +This feature introduces a fully automated, admin-triggered pipeline that synchronizes textual data from a relational database (PostgreSQL / Django ORM) to a vector database (Qdrant). The system guarantees **zero duplicate embeddings**, **crash resilience**, and seamless **A/B testing** across different embedding models — all without manual file uploads. + +| Property | Value | +| ----------------- | -------------------------------------------- | +| **Source** | PostgreSQL (Django Models) | +| **Target** | Qdrant Vector Database | +| **State Tracking**| JSONB Arrays (`embedded_in` column) | +| **Deduplication** | Deterministic Hash ID via MD5 | +| **Trigger** | Admin UI → FastAPI Background Task | + +--- + +## Architecture + +``` +┌──────────────────────┐ HTTP POST ┌──────────────────────────┐ +│ Django Admin UI │ ────────────────────▸ │ FastAPI Agent │ +│ (EmbeddingSession) │ │ /api/sync-knowledge │ +└──────────────────────┘ └────────────┬─────────────┘ + ▲ │ + │ progress updates BackgroundTask + │ (status, %, items) │ + │ ▼ +┌────────┴─────────────┐ ┌──────────────────────────┐ +│ PostgreSQL │ ◂────── read/update ──▸ │ run_global_embedding_ │ +│ embedded_in (JSONB) │ │ sync(session_id) │ +└──────────────────────┘ └────────────┬─────────────┘ + │ + embed + upsert + │ + ▼ + ┌──────────────────────────┐ + │ Qdrant Vector DB │ + │ (hybrid search collection)│ + └──────────────────────────┘ +``` + +--- + +## How It Works + +### 1. State Tracking via JSONB + +Every syncable Django model (e.g. `Article`, `Hadith`) includes an `embedded_in` column: + +```python +# Django model field +embedded_in = models.JSONField(default=list) +# Example value: ["dovodi_jina-embeddings-v4_hybrid", "dovodi_text-embedding-3-small_hybrid"] +``` + +**Why an array instead of a boolean?** A simple `is_embedded = True` flag cannot distinguish *which* model the row was embedded into. By storing the exact collection name, the system natively supports multiple embedding models simultaneously. Switching the active model in `config/embeddings.yaml` from `jina_AI` to `openai_small` causes every row to be detected as "missing" for the new collection — triggering a full, automatic re-sync. + +**Self-healing on update:** When an admin edits the text of a record in Django admin, the overridden `save()` method resets `embedded_in` to `[]`, guaranteeing the updated content is picked up in the next sync cycle. + +### 2. The Trigger Mechanism (Django → FastAPI) + +A dedicated `EmbeddingSession` model in Django tracks the lifecycle of each sync operation: + +| Field | Purpose | +| ----------------- | ------------------------------------------ | +| `status` | `PENDING` / `PROCESSING` / `COMPLETED` / `FAILED` | +| `total_items` | Total rows needing embedding | +| `processed_items` | Rows embedded so far | +| `progress` | Percentage (0–100) | +| `error_message` | Captured exception on failure | + +When the admin saves a new session, Django sends a **non-blocking** `HTTP POST` to the FastAPI agent: + +``` +POST /api/sync-knowledge +Body: { "session_id": 42 } +``` + +The FastAPI route (`src/api/routes.py`) receives this and delegates to a `BackgroundTask`: + +```python +@router.post("/api/sync-knowledge") +async def sync_knowledge(request: SyncRequest, background_tasks: BackgroundTasks): + background_tasks.add_task(run_global_embedding_sync, request.session_id) + return {"status": "started", "session_id": request.session_id} +``` + +The Django admin UI renders a **live Tailwind progress bar** powered by `processed_items / total_items`. + +### 3. The Smart Background Worker + +The core logic lives in `src/knowledge/sync_rag.py` → `run_global_embedding_sync(session_id)`: + +**Step A — Resolve the active model:** + +```python +embed_factory = EmbeddingFactory() # reads config/embeddings.yaml +embedder = embed_factory.get_embedder() # returns the default embedder +vector_db = get_qdrant_store(embedder=embedder) +active_collection_name = vector_db.collection +``` + +The collection name is dynamically composed as `{BASE_COLLECTION_NAME}_{model_id}_hybrid` (e.g. `dovodi_jina-embeddings-v4_hybrid`). + +**Step B — Query only missing rows:** + +Using PostgreSQL's native JSONB containment operator (`@>`), the system fetches *only* the rows whose `embedded_in` array does **not** contain the active collection name: + +```sql +SELECT * FROM article_article +WHERE NOT (CAST(embedded_in AS jsonb) @> CAST('["dovodi_jina-embeddings-v4_hybrid"]' AS jsonb)) +``` + +This is the key to incremental sync — already-embedded rows are never touched. + +**Step C — Process, embed, upsert:** + +For each pending row, the worker: + +1. Formats the record into a continuous string (`TITLE: ... \n CONTENT: ...`) +2. Generates a **deterministic Qdrant ID** (see below) +3. Wraps it in an Agno `Document` and calls `vector_db.upsert()` +4. Updates the row's `embedded_in` array in PostgreSQL +5. Reports progress to the `EmbeddingSession` every 5 items + +### 4. Deterministic Deduplication + +To prevent duplicate vectors when resuming a crashed sync or re-embedding updated text, auto-generated UUIDs are **not used**. Instead, the system computes a deterministic ID: + +```python +hash_input = f"{data_type}_{row.id}_{active_collection_name}" # e.g. "ARTICLE_42_dovodi_jina-embeddings-v4_hybrid" +hash_id = hashlib.md5(hash_input.encode()).hexdigest() +qdrant_id = str(uuid.UUID(hash_id)) # valid UUID from MD5 +``` + +This ID is passed as `content_hash` to `vector_db.upsert()`, which causes Qdrant to **overwrite** any existing point with the same ID rather than creating a duplicate. + +### 5. Closing the Loop + +After a successful upsert, the worker appends the active collection name to the row's `embedded_in` array: + +```sql +UPDATE article_article +SET embedded_in = CAST(embedded_in AS jsonb) || CAST('["dovodi_jina-embeddings-v4_hybrid"]' AS jsonb) +WHERE id = 42 +``` + +Once all tables are processed, the session status is set to `COMPLETED`. If any exception occurs, the status is set to `FAILED` with the error message captured. + +--- + +## File Reference + +| File | Responsibility | +| --- | --- | +| `src/knowledge/sync_rag.py` | Core sync logic — queries missing rows, embeds, upserts, updates state | +| `src/api/routes.py` | FastAPI endpoint `/api/sync-knowledge` that triggers the background task | +| `src/main.py` | Application factory — includes the API router | +| `src/knowledge/embedding_factory.py` | Reads `config/embeddings.yaml` and instantiates the correct embedder | +| `src/knowledge/vector_store.py` | Builds the Qdrant client with dynamic collection naming | +| `config/embeddings.yaml` | Declares available embedding models and the active default | + +--- + +## Configuration + +The active embedding model is controlled by `config/embeddings.yaml`: + +```yaml +embeddings: + default: jina_AI # switch to "openai_small" to trigger full re-sync + + models: + openai_small: + provider: "openai" + id: "text-embedding-3-small" + dimensions: 1536 + api_key: ${OPENAI_API_KEY} + + jina_AI: + provider: "jinaai" + id: "jina-embeddings-v4" + dimensions: 1024 + api_key: ${JINA_API_KEY} +``` + +Changing `default` from one model to another is all that is needed — the sync worker will detect that no rows contain the new collection name and re-embed everything. + +--- + +## Why This Design is Production-Ready + +| Property | Detail | +| --- | --- | +| **Zero data duplication** | Deterministic MD5 hashing ensures the same row always maps to the same Qdrant point ID. Re-running sync never creates duplicates. | +| **Seamless model switching** | Changing the embedding model in YAML causes the system to treat all rows as "missing" for the new collection. No manual migration needed. | +| **Crash resilience** | State is committed row-by-row to PostgreSQL. If the server crashes at 99%, restarting picks up the remaining 1%. | +| **Cost efficiency** | Only un-embedded rows hit the AI API. Already-processed data is never re-sent, saving API costs. | +| **Non-blocking UI** | The Django admin fires an async HTTP call and renders live progress — the UI never freezes. | +| **Multi-table support** | The `tables_to_sync` list can be extended with new Django models without touching the core algorithm. | diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..5b96fa0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +# Welcome to the Dovoodi Agent Docs + +This documentation covers the architecture, setup, and maintenance of the Dovoodi Agent microservice. + +### Quick Links +* If you are looking for how the data syncs from Django to Qdrant, see the [Incremental Vector Sync](INCREMENTAL_VECTOR_SYNC.md) guide. +* For prompt engineering details, check the [Dynamic System Prompt](DYNAMIC_SYSTEM_PROMPT.md). \ No newline at end of file diff --git a/out.md b/out.md index a42c319..0d70517 100644 --- a/out.md +++ b/out.md @@ -11,4 +11,22 @@ deepseek v3 : -بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ\n\nدر منابع حدیثی، روایاتی درباره واقعه غدیر خم نقل شده است که در آنها پیامبر اکرم صلی الله علیه وسلم درباره حضرت علی رضی الله عنه فرمودند:\n\n**«مَنْ كُنْتُ مَوْلَاهُ فَعَلِيٌّ مَوْلَاهُ، اللهُمَّ وَالِ مَنْ وَالَاهُ وَعَادِ مَنْ عَادَاهُ»**\n\nترجمه: \"هر کس من مولای او هستم، علی مولای اوست. خدایا، دوست بدار هر که او را دوست بدارد و دشمن بدار هر که با او دشمنی کند.\"\n\nاین روایات در کتاب **المعجم الکبیر** اثر الطبرانی با اسناد مختلف نقل شده است.\n\nو الله أعلم. \ No newline at end of file +بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ\n\nدر منابع حدیثی، روایاتی درباره واقعه غدیر خم نقل شده است که در آنها پیامبر اکرم صلی الله علیه وسلم درباره حضرت علی رضی الله عنه فرمودند:\n\n**«مَنْ كُنْتُ مَوْلَاهُ فَعَلِيٌّ مَوْلَاهُ، اللهُمَّ وَالِ مَنْ وَالَاهُ وَعَادِ مَنْ عَادَاهُ»**\n\nترجمه: \"هر کس من مولای او هستم، علی مولای اوست. خدایا، دوست بدار هر که او را دوست بدارد و دشمن بدار هر که با او دشمنی کند.\"\n\nاین روایات در کتاب **المعجم الکبیر** اثر الطبرانی با اسناد مختلف نقل شده است.\n\nو الله أعلم. + + + + + + +---------------------------------------- + + +Here is the context from the database:\n---------------------\n[Source: Unknown | Relevance: 0.10]\nCATEGORY: آداب زيارت\nWIKI TITLE: زیارت امام رضا؛ آداب معنوی و روحانی\nAUTHOR: Unknown\nCONTENT:\nدر بیان بعض اعمال مهمه در حرم مطهر رضویبدانکه :معنی زیارت ملاقات و دیدن است از شخص زنده یا مرده به اینکه انسان هر جا باشد چه دور و چه نزدیک قصد دیدن و ملاقات نماید و بهر کیفیت بشود خود را نزد آن شخص برساند و چون خود را حضور مزور رسانید زیارت به عمل آمده و او را می توان گفت زائر چه آنکه سلام بدهد یا ندهد و چه با مزور خود سخن بگوید یا نگوید در هر حال دیدن و ملاقات حاصل شده است.لكن هر مزوری را مقام و مرتبه و درجه ایست که شایسته است زائر مراعات آن مقام و منزلت را بنماید مثلاً فرق بسیاری است بین اینکه انسانی به دیدن یکی از خویشان یا یکی از دوستان خود می رود که از حیث شانیت مانند خودش یا پست تر از خودش میباشد و بین دیدن و ملاقات شخص عالم جلیلی یا حاکم شهری یا پادشاه زمانی پس شخص زائر البته بایستی متوجه مقام و شان مزور خود باشد و با آداب لازمه رفتار نماید و چو این مطلب واضح شد عرض میکنم.ما شیعه اثنی عشری میدانیم در همه عوالم ایجاد هیچ کس به مقام و جلال و عظمت محمد و آل طاهرینش نرسیده و نمیرسد و نیز می دانیم که حیات و ممات ایشان یکسان است.و لذا کسی که با چنین اعتقاد کامل توجه به ایشان میکند یا حضور قبور ایشان میرود و میرسد بایستی بسیار مؤدب باشد به آدابی که علماء بزرگ تذکر داده اند و ما قبلاً به بعض آنها اشاره کردیم و اینک در اینجا به چند امر مهم دیگر۲۱5تذکر می دهیم.اول:آنکه کسی که پیغمبر خدا یا فاطمه زهرا یا یکی از ائمه معصومین را زیارت میکند بایستی تمام توجهش به مزورش باشد پس خلاف ادب است که توجه به دیگری کند یا با کسی سخن بگوید مگر لازم شود که امری یا نهیی نماید و نیز خلاف ادب است که توجه به این طرف و آن طرف کند و به اوضاع و اسباب حرم یا به مردم نگاه کند.دومدر روضه مطهره در حضور امام از کسی سئوال نکند و چیزی طلب ننماید زیرا که چیز خواستن از غیر در حضور مبارک امام و حجت خدا خلاف ادب است دیگر آنکه از هر کس چیز بخواهد خود مسئول مانند سائل محتاج به امام است و شایسته این است که هر چه میخواهد از امام بخواهد و امام را شفیع خود گرداند تا امام شفاعت فرماید نزد خدای تعالی و آن وقت سائل به حاجت خود نائل گردد و به مقصود برسد.شاهد بر این مطلب روایتی است که بعضی از بزرگان نقل کرده اند و در مفاتیح نیز مذکور است از حضرت امام زین العابدين و سيد الساجدين که آن حضرت در روز عرفه سائلی را دید که از مردم چیزی طلب میکرد آن بزرگوار به او فرمود ای شخص وای بر تو چرا از غیر حق تعالی سئوال میکنی در چنین روزی که امیدواری هست از برای طفلانی که در شکم مادرانند و هنوز به دنیا نیامده اند و زبان سئوال ندارند که در این روز سعادتمند بشوند.(یعنی در این روز رحمت الهی شامل حال جميع مردم می شود حتی طفلهائی که در شکم مادرانند و زبان سئوال ندارند.۲۱۶پس امید رحمت بر ایشان از درگاه حضرت پروردگار هست پس چرا کسانی که زبان سئوال دارند از دربار پادشاه بی نیاز و خدای چاره ساز سئوال نکنند و از دیگری که خود محتاج است سئوال کنند لذا شایسته است که شخص سائل و محتاج پیوسته زبان حال و مقالش به درگاه خالق معبود چنین باشد.رباعییارب یک حاجتی و روحی بیدیکاعرضت عن الغير و اقبلت الیکمالی عمل صالح استظهر بهقد جئتك راجياً توکلت علیکسومخواندن دو رکعت نماز در بالا سر مبارک آن حضرت و در قنوت حاجات خود و حاجات همه اهل ایمان را از درگاه حضرت قاضی الحاجات در خواست نماید که البته به اجابت مقرون خواهد شد.چنانکه شیخ ما در مفاتیح الجنان فرماید به سند معتبر از حضرت هادی امام على نقى منقول است که هر که را به سوی خدا حاجتی باشد پس زیارت کند قبر جدم حضرت امام رضا الله را در شهر طوس در حالتی که غسل کرده باشد و آنگاه نزد سر آن حضرت دو رکعت نماز به جای آورد و در قنوت نماز حاجت خود را طلب کند به درستی که دعای او مستجاب و مسئلتش مقرون به اجابت خواهد شد مگر آنکه از برای گناهی یا قطع رحمی سئوال کند به درستی که موضع قبر آن حضرت بقعه ایست از بقعه های بهشت و هیچ مؤمنی او را زیارت نمیکند مگر آنکه حق تعالی او را از آتش جهنم آزاد میکند و داخل بهشت میگرداند.حقیر گویداحتمال میرود که این نماز نماز زیارت باشد و احتمال می رود که این دو رکعت غیر نماز زیارت باشد بلکه نماز حاجت باشد در هر حال مستحب است که زائر بعد از زیارت دو رکعت نماز زیارت بخواند و ظاهراً نماز زیارت به منزله هدیه ایست که شخص زائر برای مزور خود که وجود مقدس معصوم است۲۱۷هدیه می نماید مانند کسی که میخواهد نزد بزرگی یا سلطانی برود، پس یک ارمغان و هدیه ای تهیه میکند برای او و با خود میبرد که باعث تقرب او شود نزد آن بزرگ و از آنجایی که امتعه و اموال دنیا نزد امام به قدر بال مگسی ارزش ندارد از این جهت دو رکعت نماز را زائر به جای می آورد.سپس ثوابش را هدیه روح شریف امام خود مینماید و البته این عمل باعث قرب او نزد امام میشود و هم فوائد و ثوابش به خود او خواهد رسید.در کتاب ابواب الجنان(۱) ۱ - این کتاب در ادعیه ایام و لیالی و ساعات است تألیف سید ابو القاسم بن سید ابراهيم معروف بمحرر متوفی ۶ ع ۲ - ۱۳۷۰ مدفون در نجف حجره ملصق به باب طوسی چنانکه در نقباء البشر است. )گوید مروی است که فرمود هر که ثواب نماز خود را برای رسول خدا و امیرالمؤمنین و اوصیاء بعد آن حضرت قرار دهد حق تعالى ثواب آن نماز را آنقدر مضاعف گرداند که از شمردن آن نفس قطع شود و پیش از آنکه روح از بدنش بیرون گردد به او گویند هدیه تو به ما رسید و امروز روز جزا و مکافات تو است خوشحال باش و چشمت روشن باد به آنچه خدا برای تو مهیا کرده و گوارا باد برای تو آنچه را به آن رسیدی الخ.حقیر گویدظاهراً این نماز هدیه غیر نماز زیارت است اگر چه نماز زیارت نیز هدیه است لکن این نماز هدیه هر جا باشد و هر وقت باشد می توان به جای آورد و بهتر این است که قبل از نماز تکبیرات افتتاحیه را بخواند و پس از تسبیح رکوع و سجود سه مرتبه بگوید صلى الله على محمد و آله الطيبين الطاهرین و بعد از سلام ثواب این دو رکعت نماز را به روح هر یک از محمد و آلش که می خواهد نثار و هدیه نماید به اینکه به درگاه الهی بگوید.اللهم انت السلام و منك السلام و اليك يعود السلام حينا ربنا منك بالسلام اللهم ان هاتين الركعتين هدية منى الى ولیک فلان و به جای فلان نام شریف هر کدام از معصومین را که میخواهد ببرد مثلاً بگوید الی ولیک علی بن موسی الرضا.۲۱۸پس از آن بگوید «فصل علی محمد و آله و بلغه اياها و اعطنی افضل املی و رجائی فيك وفي رسولك وفيه» .چهارمهر قدر بتواند به قصد نیابت از جانب آن حضرت از قرآن مجید تلاوت کند و ثوابش را هدیه نماید که بسیار فائده دارد.پنجماز خواندن نماز جناب جعفر طیار رضوان الله عليه غفلت ننماید چه آنکه در كتاب شريف مفاتيح الجنان فرموده است:علامه مجلسی علیه الرحمه نقل کرده از خط شیخ جليل شيخ حسين بن عبد الصمد والد مرحوم شیخ بهائی که شیخ ابوالطیب حسین بن احمد فقیه رازی رحمة الله ذكر نموده که هر کس زیارت کند حضرت امام رضا یا دیگری از ائمه هداة مهدیین را پس نماز جعفر را نزد آن امام بزرگوار به جای آورد برای او نوشته شود بهر رکعتی ثواب کسی که هزار حج و هزار عمره به جا آورده باشد و هزار بنده را در راه خدا آزاد کرده باشد و هزار مرتبه به جهاد ایستاده باشد با پیغمبر مرسل و برای او است بهرگامی که بر میدارد ثواب صد حج و صد عمره و صد بنده آزاد کردن در راه خدای تعالی و نوشته شود برای او صد حسنه و محو شود از او صد سئيه.(اللهم وفقنا لاتيان هذا العمل الشريف )ششم:شایسته است همیشه شب و روز خوانده شود در همه جا خصوص در حرم مطهر آن حضرت دعای عافیتی که خود آن بزرگوار خوانده چنانکه در عیون است.۲۱۹که راوی گفته است من در خدمت حضرت رضا بودم در طواف چون به مقابل رکن یمانی رسیدیم آن حضرت ایستاد و هر دو دست خود را بلند کرد و شروع فرمود به خواندن این دعايا الله يا ولى العافية و يا خالق العافية و يا رازق العافية و المنعم بالعافية والمنان بالعافية والمتفضل بالعافية على وعلى جميع خلقك يا رحمن الدنيا والآخرة ورحيمهما صل على محمد و آل محمد و ارزقنا العافية ودوام العافية وتمام العافية وشكر العافية في الدنيا و الاخرة يا ارحم راحمين.هفتمشایسته است که نماز خود آن حضرت نیز در حرم مطهرش خوانده شود و آن چنانکه در مفاتیح و غیر آن ذکر شده شش رکعت است هر دو رکعت به یک سلام و در هر رکعت بعد از سوره حمد ده مرتبه سوره مباركه هل اتى على الانسان و دعای آن حضرت این است:یا صاحبي في شدتي و يا وليى فى نعمتى و يا الهى واله ابراهیم و اسماعیل و اسحاق و يعقوب يا رب كهيعص ويس و القرآن الحکیم اسئلک یا احسن من سئل و يا خير من دعى و یا اجود من اعطی و یا خیر مرتجى اسئلك ان تصلى على محمد و آل محمد.بدانکه این دعا چنانکه نقل شده است تمام شد لکن واضح است که بعد از ان تصلى على محمد و آل محمد خواننده دعا حاجاتش را طلب کند مؤلف ناچیز هم التماس دعا دارد.هشتمسزاوار و مناسب است که در حرم مطهر خوانده شود دعای خود حضرت رضا صلوات الله علیه چنانکه در باب ششم کتاب عیون است:در روایت مفصله ای که رسول خدا دعاهای هر یک از فرزندانش را از۲۲۰حضرت سید الشهداء تا امام حسن عسکری بابی بن کعب تعلیم می دهد هر کس طالب آن ادعیه باشد به کتاب عیون مراجعه نماید و مقصود ما در این جا دعای حضرت ثامن الائمه است و آن این است.اللهم اعطنى الهدى و ثبتنى عليه و احشرني عليه آمنا امن من لا خوف عليه ولا حزن و لا جزع انك اهل التقوى و اهل المغفرة پس سزاوار است زائر و مجاور همیشه این دعای شریف را بخواند.نهم:از جمله امور مهمه در حرم مطهر این است که زائر غفلت نکند از دعا کردن برای پدر و مادر و خویشان و بستگان و اهل بلد خود از مرده و زنده بلکه تمام اهل ایمان را از احیاء و اموات دعاء کند و دیگر آنکه برای ایشان به امام سلام عرض کند و اگر همت کند چنانکه بعض بزرگان چنین میکردند به نیت هر یکی یک سلام عرض کند و هرگاه چنین نمیکند برای همه یک سلام بدهد بلکه برای تمام اهل ایمان از زمان حضرت آدم تاکنون یک سلام بدهد بلکه برای اهل ایمانی که بعد از این زمان تا آخر دنیا خواهند آمد سلام عرض نماید و برای همه دعا کند.دهمو نیز غفلت نکند بعد از زیارت و نماز در حرم مطهر از خواندن دعای شریف عالية المضامین که در ملحقات مفاتیح الجنان است زیرا که در آن دعا خوبیهای دنیا و آخرت جمع است و بسیاری از زائرین از آن دعا غفلت دارند و اول آن این است اللهم انى زرت هذا الامام مقرا بامامته معتقداً لفرض طاعته الخ.یازدهمو نیز بخواند دعائی که منسوب است به حضرت بقية الله امام عصر عجل الله۲۲۱تعالی فرجه که اولش این است اللهم ارزقنا توفیق الطاعة وبعد المعصية الخ .آن نیز در مفاتیح قبل از اعمال رجب ذکر شده.دوازدهمو نیز قبل از نماز خصوص در حرم مطهر بخواند صلوات بر آن حضرت را که در مفاتیح فرموده ابن قولویه از بعض ائمه روایت کرده که فرمودند چون نزد قبر امام رضا الله بروی بگو اللهم صل على على بن موسى الرضا المرتضى الامام التق النق و حجتك على من فوق الارض و من تحت الثرى الصديق الشهيد صلوة كثيرة تامة زاكية متواصلة متواترة مترادفة كافضل ما صليت على احد من اوليائك.سیزدهم:بدانکه زیارت حضرت رضا نظر به روایتی که ذکر شد در بیست و چهار ساعت شبانه روز مستحب است و اطلاق روایات بر این معنی گواه بزرگی است.لكن البته بعض اوقات که تعلقی به آن سرور داشته باشد می توان گفت مناسبتش بلکه فضیلتش بیشتر است مانند وقت ولادت و شهادت و ولایتعهدی به اختلاف زیادی که در آنها هست پس هر وقت که احتمال ولادت و شهادت و ولا يتعهدی داده شود مناسب است زیارت آن حضرت و بعض بزرگان تصریح نموده اند که در چند وقت فضیلت زیارت آن حضرت بیشتر است.یکی بیست و سوم ذی القعده چنانکه سید بن طاوس علیه نقل نموده و یکی بیست و پنجم ذی القعده و دیگر اول رجب چنانکه هر دو را میر داماد علیه الرحمه ذکر فرموده در رساله ای که نامیده شده به اربعه ایام و آن به طبع نرسیده لکن مخطوط آنرا که دیده ام عبارت آن مرحوم را نقل مینمایم در ذکر روز دحو الارض که ۲۵ ذی القعده است فرماید زیارت سیدنا و مولانا امام الورى و منار الهدى ابي الحسن على بن موسى الرضا عليه من الصلوة انماها و من التسليمات از كاها.۲۲۲در این روز افضل اعمال مستحبه و اوکد (اکدظ) آداب مسنونه است و همچنین زیارت آن حضرت در روز اول رجب الفرد به غایت مؤكد و محثوث عليه است.و دیگر در منهاج العارفین تألیف سید محمد حسن بن سید محمد عسکری حسینی سمنانی گوید روز نیمه رجب و شبش زیارت امام حسین و حضرت رضا وارد شده انتهى.و در مفاتیح در اعمال ماه رجب فرموده در ماه رجب زیارت حضرت رضا مندوب است و اختصاصی دارد چنانچه عمره در این ماه فضیلت دارد انتهى.حقیر گوید:ظاهراً مأخذ این فرمایش روایتی است که نیز در مفاتیح در باب فضیلت زیارت امام رضا نقل نموده که محمد بن سلیمان از امام محمد تقی پرسید که شخصی حج واجب خود را به عنوان حج تمتع به جای آورده پس به مدینه رفته و زیارت نموده رسول خدا را آنگاه به نجف رفته و زیارت کرده پدرت امیرالمؤمنین را و حق او را شناخته و میدانسته که او حجت خداست بر خلق خدا و او درگاه خداست که از آن در به خدا باید رسید پس سلام کرده بر آن حضرت و رفت به کربلا و حضرت امام حسین الله را زیارت کرد پس رفت به بغداد و حضرت موسی بن جعفر کاظم را زیارت کرد آنگاه به شهر خود برگشت.و در این وقت خدای تعالی آن قدر مال به او روزی فرمود که می تواند باز به حج برود حال برای این مرد که حج واجب خود را به جای آورده بهتر است که باز به حج برود.یا برود خراسان و پدرت امام رضا را زیارت کند فرمود بلکه برود بر پدرم سلام کند افضل است و باید در ماه رجب باشد و در این زمان زیارت نکند که بر ما و شما از خلیفه خوف تشنیع هست تمام شد روایت.حقیر گویدعبارت کتاب کامل الزیارات در ص ۳۰۶ چنین است و لیکن۲۲۳ذلك في رجب ولكن لا ينبغي ان يفعلوا هذا اليوم فان علينا وعليكم خوفا من السلطان و شنعة.یکی از علماء بزرگ در اینجا سخن متینی دارد که فرموده است عبارت این روایت در کامل الزيارات و عيون و لیکن ذلك في رجب با جیم نقطه دار است و لکن در نروع کافی که روایت را نقل نموده و لیکن ذلک رحب به حاء بی نقطه است و رجب به معنی فراخی است که ضد فشار و سختی است و این اصح است به قرینه عبارت بعد که فرمود و در این زمان نروید که از خلیفه بر شما خوف است.چهاردهماز جمله آداب زیارت و وظایف زائر وداع مزور است یعنی زیارت کننده بعد از زیارت و رسیدن به مقصد هنگامی که میخواهد از خدمت امام خود به بلد و جای سکونت خود برگردد و از نزد قبر شریف آقا و محبوب خود دور شود وداع کند و سلام خدا حافظی عرض نماید و بخواند آنچه در کتب زیارات ذکر شده و می تواند اكتفاء کند به اینکه بگوید چنانکه حضرت صادق در وداع قبر پیغمبر خدا به يونس بن یعقوب فرمود بگو صلى الله علیک السلام علیک لا جعله الله آخر تسلیمی یا اینکه بگوید استودعكم الله ولا جعلكم الله اخر العهد من زيارتكم و السلام عليكم و رحمة الله و برکاته یا بگوید چنانکه در دعای بعد از زیارت ائمه الام است که چون زیارت نمودی و خواستی برگردی بگو السلام علیکم یا اهل بيت النبوة ومعدن الرسالة سلام مودع لاسئم ولا قال و رحمة الله و بركاته.ناگفته نماند که از جمله مستحبات که بسیار در اسلام تاکید شده است افشاء سلام است یعنی شخص مؤمن به هر کس از اهل ایمان برسد سلام بدهد حتی در روایت است که بخیل ترین مردم آن کسی است که از سلام گفتن بخل نماید و خدایتعالی چه قدر ثواب برای این عمل مرحمت می فرمایدافسوس که در این دوره و زمان ما مستحباتی که بسیار نتیجه و فایده دارند کم۲۲۴شده و یا گم شده یعنی از بین رفته است و در روایت است که هرگاه کسی رسید و وارد شد و سلام نداده مشغول سخن شد او را جواب ندهید و نیز در روایت است.اذا دخلت البيت فان كان فيه احد فسلم عليهم والا فقلهرگاه داخل خانه ای شدی اگر کسی در آنجا بود سلام به او بده و اگر کسی نیست بگو السلام علينا من عند ربنا و دیگر از مستحبات که ترک شده است . سلام دادن وقت جدائی و مفارقت مؤمن است از مؤمن که آنرا سلام وداع میگویند یعنی سلام خداحافظی و پوشیده نماند که سلام وداع شایسته است برای هر زائری چه زائری که از راه دور به عنوان زیارت مشرف شده و چه مجاوری که به زیارت آمده و می خواهد از حرم و از نزد قبر دور شود و خارج گردد و بسیاری از زائرین خصوص زائرین مجاورین از این مطلب غفلت دارند بالجمله چون زائر میخواهد از حرم مطهر بیرون شود وداع کند امام خود را که شاید بار دیگر موفق نشود زیرا که مرگ خبر نمی دهد چه وقت خواهم آمد.و چه نیکو گفته است شاعرچو رسی بکوی دلبر بسپار جان و مگذرکه مباد بار دیگر نرسی بکوی دلبرولا یخفی که حالات زائرین هنگام وداع زیارت امام بسیار مختلف است نظر به اختلاف درجات معرفت و محبت زائرین به ساحت قدس حجت بالغة الهيه همان قسمی که بعض زائرین با شوق تمام و دل مملو از محبت و ارادت و حال خضوع و خشوع و چشم پر اشک و با کمال ادب خودشان را می رسانند به دربار فیض آثار امام هنگام رفتن و جدا شدنشان از حضور قبر امام انقلاب حال و گریه ایشان بیشتر است چه آنکه میخواهند از خدمت عزیزترین خلق خدا دور شوند و به فراق محبوب خود دچار کردند.و این حقیر عرض میکند که اگر کسی هنگام وداع بخواهد بیشتر قلبش و دلش بسوزد و اشکش زیادتر بریزد یاد کند وداع جد آن بزرگوار حضرت سید۲۲۵الشهداء الله را روز عاشورا با اهل بیت بی کس خود میان بیابان کربلا آن وقتی که آن امام مظلوم به در خیمه های اهل بیت خود صدا زد یا زینب یا ام کلثوم یا سکینه یا فاطمه عليكن منى السلام و بنا به نقل صاحب بیت(۱) ۱ - این کتاب فارسی و در احوال و مصائب خمسة النجباء است و به طبع رسیده تألیف صاحب مصائب المعصومين و مناقب المعصومين ملا عبد الخالق یزدی است متوفای ۱۲۶۲ در مشهد رضوی که از مشاهیر شاگردان شیخ احمد احسائی بوده و این بیت الاحزان غیر از بیت الاحزان عربی است که در احوال حضرت فاطمه زهرا تأليف شيخ ما محدث قمی رضوان الله علیه است. )الاحزان صدا زد:«يا اهل بيتي عليكن منى السلام هذا آخر السلام و هذا آخر الكلام فاستعددن للاسر والذل و الغربة.» ای اهل بیت من سلام من بر شما باد این آخر سلام و آخر کلام من است پس شما مهیا باشید برای دستگیری و ذلت و غربت خدا میداند در آن وقت بر اهل بیت چه گذشت و چه گونه پروانه وار دور آن شمع شبستان امامت را گرفتند و آیا زبان حال یا مقال هر کدامشان چه بوده است.در دمعة الساكبه است که آن حضرت فرمود (و کانی بكم غير بعيد يسوقونكم امام الركاب و يسومونكم سوء العذاب).گویا به همین زودی میبینم که شما را جلو شترها انداخته و می برند و شما را به سختی آزار می رسانند ( فلما سمعت زينب بكت و جرى الدمع من عينيها و نادت تا علیا مکرمه حضرت زینب این سخن برادر را شنید به گریه در آمد و اشک از دیدگانش جاری شده ناله اش بلند شد به و اوحدتاه واقلة ناصراه و اسوء منقلباه و اشوم صباحاه فشقت ثوبها. )آنگاه جامه بر تن پاره کرده و نشرت شعرها و موهای خود را پریشان کرد ولطمت على وجهها و سیلی بر روی خود زد سید الشهداء الله فرمود (مهلا يا بنت المرتضى ان البكاء طويل حاصلش این است که ای خواهر اکنون آرام بگیر و گریه۲۲۶مکن که گریه تو طولانی خواهد شد.زبان حال را صفی علیشاه(۱) ۱ - ترجمه او در جلد اول مختصرا ذکر شد. )چنین گفته:رویتمان مرا غمخوار باشدر بلایا و شدائد یار باشحق تو را خواهد اسیر از بهر آنکه نماید خاکیان را امتحانحق تو را خواهد اسیر سلسلهاز رضای حق مکن خواهر گلهرو که هستم هر کجا من همرهتآگهم از حال قلب آگهتچون شوی بر ناقه عریان سواردر بدر گردی بهر شهر و دیارنیستم غافل دمی از حال توبا سر آیم هر کجا دنبال توچون خرابه گشت جایت شاد باشتا که گنج حق شود بر خلق فاشگنج توحیدی تو از ویران مرنجزانکه در ویرانه باشد جای گنجرو پرستاری کن آن بیمار رازان دل بیمار جو دلدار راچون دل بیمار من خسته تر است.من در آنم چونکه بشکسته تر استدر دل بیمار شده مأوای منخاصه بیماری که خفته جای منهان برو زینب که دردت بی دواستدردمند حق طبیب دردهاسترو صبوری و اسیری پیشه کنریشه بی طاقتی را تیشه کنگر خورد سیلی سکینه دم مزنعالمی از آن دم زدن بر هم مزندر فراقت از تو هستم عذر خواهرو که رفتم حق تو را پشت و پناهو نیز در دمعة الساكبه است که چون آن امام مظلوم روبراه گذاشت عقیله بنی هاشم زینب کبری خود را به برادر رسانید و آن حضرت را گرفت و عرض کرد(مهلا یا اخی حتی از ود من نظری و اودعك وداع مفارق لا تلاقى بعده)***۲۲۷شعرمهلا اخي قبل الممات هنيئة ***لتبرد منى لوعة وغليلیعنی ای برادر آرام بگیر و آهسته برو تا خواهرت پیش از مرگ زاد و توشه ای از دیدارت بردارد و با حضرتت وداع و خداحافظی کند و داعی که بعد از آن ملاقاتی نخواهد بود.شعرتو میدان میروی بی لشکر ای شاهبرادر جان خدا بادت به همراهسبکتر زن رکاب مرکب خویشکه زاشک چشم زینب بسته شد راهمنه شاها از این خرگه برون پایکه ترسم پا نهد دشمن بخرگاهالا ای یوسف زهرا حذر کناز این وادی از این گرگان از این چاهمکن رو جانب میدان که ترسمبخون رنگین شود این روی چون ماهو گرمی بایدت رفتن بناچارفانی اشتكى حزني الى اللهبسوزم از فراقت صبح تا شامبنالم از غمت شب تا سحرگاهدر این وادی کشیم ای شاه خوبانتو تیر از سینه و از سینه من آهو نیز در دمعه گوید:«فجعلت تقبل يديه و رجليه واحطن به سائر النسوان و يقبلن يده و رجله » میگوید آنگاه علیا مکرمه زینب دستها و پای برادر را بوسید و مخدرات دیگر هم همه دور آن حضرت را گرفته و دست و پای آن سرور را بوسیدند.شعرمرو مرو که فلک کارش اعتبار نداردمرو که بیگل رویت دلم قرار نداردعزیز من چو برابر شدی به لشکر دشمنبگو که خواهر من تاب انتظار نداردبدرد بی کسیم مبتلا مکن بفدایتکه خواهر تو کسی را در این دیار نداردز گریه ام منما منع ای عزیز پیمبردل شکسته ام از گریه اختیار ندارداگر چه عابد زارت رضا بود به اسیریولیک طاقت اشتر شود سوار ندارد۲۲۸و خدا رحمت کند یکی از علماء معاصرین ما مرحوم حاج شیخ علی امام جمعه کاشمری مولود ۱۳۰۰ متخلص به مشکوة متوفای ۱۳۷۴ ابن محمد باقر چه نیکو گفته است در این مقام زبان حال عمه سادات را.ای راکب فرخنده نگه دار عنان رادریاب من خسته بی تاب و توان راآهسته تر ایشاه که تا سیر ببینمبار دگر آن راحت دل قوت جان راآرام تر ای یوسف ثانی که زهر سوگرگان از پی قتل تو بر بسته میان رابر لشکر اعدا بنگر کز پی قتلتبگرفته بکف خنجر و شمشیر و سنان رالب تشنه روانی سوی میدان شهادتبر دیده خواهر بنگر سیل روان رالیلای جگر خون چه کند با غم اکبرتسکین نتوان داد زن مرده جوان را«فعلی ظالمي آل محمد لعنة الله والملائكة والناس اجمعين »\n\n[Source: Unknown | Relevance: -0.02]\nCATEGORY: کرامت و معجزه در نيشابور\nWIKI TITLE: رضا (ع) چشمه‌ای در دل بیابان آشکار کرد\nAUTHOR: Unknown\nCONTENT:\nچشمه حضرت رضا علیه السلامدر کتاب عیون الاخبار الرضا باب خروج حضرت رضا (ع) از نیشابور به توس، حدیثی از عبدالسلام هروی روایت کرده که می گوید: وقتی که حضرت علی بن موسی الرضا (ع)\n\nاز نیشابور به جانب مأمون در مرو بیرون شدند، به ده سرخ رسید دهی است مابین نیشابور و مشهد در نیم فرسخی شریف آباد حضرت فرود آمد و فرمود آب بیاورند. به عرض رسانیدند که آب با ما نیست چون آب نبود حضرت به دست خود زمین را کاویدند و از آن چشمه آبی ظاهر شد با آن آب وضو گرفت.\n\nهم اکنون اثر این چشمه باقی است. حضرت از آن جا به جانب سناباد توس روانه شدند.\n\nحضرت علی ابن موسی به سناباد که رسیدند پشت به کوهی نمود که حالا از سنگ آن انواع مختلف ظرف غذاپزی و وسایل دیگر می سازند، فرمود: بار خدایا به وسیله این کوه مردم را بهره مند و برکت بده در آن چه قرار میدهند ظرفهای ساخته شده از این کوه پس غذای مرا فقط در همین ظرفها بپزید. مردم به برکت حضرت علی بن موسى الرضا (ع)\n\nاز آن روز متوجه این کار شدند و اثر این دعای حضرت نیز آشکار گردید.از آنجا به توس و سناباد به خانه حمید بن قحطبه طائی وارد شد. داخل قبه ای که هارون در آنجا دفن شده بود گردید و با دست مبارک یک قسمت از زمین را خط کشید و فرمود این مکان محل دفن من است.\n\nفرمودند: من در آن مکان پنهان میشوم رسول خدا (ص) فرمودند: سيجعل الله هذا المكان مختلف شیعتی و اهل مجتبی و الله .\n\nمنهم و لا يسلم على مسلم الا وَجَبَ لَهُ غُفْرانُ اللَّهِ وَ رَحْمَةٌ شَفَاعَتِنا.خداوند این مکان را محل رفت و آمد شیعیان و دوستان من خواهد گردانید. به خدا سوگند هر که مرا زیارت کند و سلام به من بدهد، مشمول مغفرت و رحمت پروردگار خواهد شد به واسطه شفاعت ما خاندان و یزورنی پس از آن چند رکعت نماز خواند و دعاهایی نموده و سجده ای طولانی کرد، پانصد مرتبه در آن سجده ذکر گفت، آن گاه خارج شد.\n\n[Source: Unknown | Relevance: -0.03]\nCATEGORY: پيشگويی شهادت خود\nWIKI TITLE: امام رضا؛ پیشگویی شهادت در طوس\nAUTHOR: Unknown\nCONTENT:\nو) پیشگویی امام از شهادتشخود امام نیز در موقعیتهای مختلفی از شهادت خویش خبر دادند در دیدار با یاران و کسانی که به نحوی از مسأله ولایتعهدی ایشان مسرور شده یا ناراحت میشدند و حتی در مقابل امر اجباری ولایتعهدی در برابر مأمون به فرجام آن اشاره می نماید.۱ مکان شهادتابوصلت هروی روایت کرده است به همراه امام رضا وقتی به سناباد طوس رسیدیم، امام داخل قبه ای شد که قبر هارون در آنجا بود در پیش قبر او خطی کشید و فرمود: این تربت من است و من در اینجا مدفون خواهم گردید و حق تعالی این مکان را محل ورود شیعیان و دوستان من خواهد گردانید\n\n(۲).(جلاء العيون، ص ۱۹۳۵ وسائل الشيعه، ج ۱۴، باب ۸۲، ص ۵۵۹ بحار الانوار، ج ۴۹ باب ۱۲، ص ۱۲۵ هذه تربنی و فيها أدفن و سيجعل الله هذا المكان مختلف شیعتی و اهل محبتی)\n\nامام سپس رو به قبله نموده و چند رکعت نماز به جا آورد و دعای بسیار خواند، سپس سجده طولانی بجا آورد و در همان حالت پانصد بار ذکر تسبیح (سبحان الله) گفت\n\n(3).(جلاء العيون، ص ۹۳۵)\n\nدر جای دیگر آمده آن حضرت ضمن خبر شهادت خویش فرمودند:من مدفون میشوم در کنار قبرها رون و خدا تربت مرا محل تردد شیعیان و دوستان من خواهد کرد\n\n(4).(منتهی الامال، ج ۲، ص ۵۳۳)\n\nهنگامی که دعبل خزاعی - شاعر اهل بیت در شهر مرو خدمت امام رسید، آن حضرت به او فرمودند: روز و شب سپری نخواهد شد تا آنگاه که طوس محل رفت و آمد شیعیان و زائران قبرم خواهد شد\n\n(۱).(بحار الانوار، ج ۹۹ باب ۴، ص ۳۹، چاپ بیروت)\n\n، اعلام الورى، ص ۳۳۰؛ عيون الاخبار الرضا، ج ۲، باب ۶۶ ص ۲۶۴: وسائل الشيعه، ج ۱۰، ص ۴۳۸ : کمال الدین، ج ۲، باب ۲۵، ص ۱۳۷۴ مناقب، ج ۴، ص ۱۳۳۹ (لا تنقضي الايام والليالي حتى تصير طوس مختلف شیعتی و زواری ... .) در روایت دیگری آمده که امام رضا الله فرمود:در خراسان بقعه ای است که زمانی خواهد رسید که محل رفت و آمد ملائکه میگردد...\n\n(2).(بحار الانوار، ج ۹۹، ص ۳۱ چاپ بیروت)\n\n؛ عیون اخبار الرضا، ج ۲، باب ۶۶ حدیث ۵ ص ۶۲۸: (ان بخراسان بقعه يأتي عليها زمان تصير مختلف الملائكة .....) در جای دیگر امام اشاره به مدفن خویش نموده و فرمود:این بارگاه بوستانی از بوستانهای بهشت است و محل آمد و شد فرشتگان آسمان و همواره محل تردد ملائکه تا هنگام دمیدن صور میباشد\n\n(3).(بحار الانوار، ج ۹۹ باب ۴، ص ۴۴ ( چاپ بیروت)\n\n. .... و هذه البقعة روضة من رياض الجنة و مختلف الملائكة لا يزال فوج ينزل من السماء وفوج يصعد إلى أن ينفخ في الصور) مستدرك الوسائل ج ۱۰، باب ۶۵، ص ۳۵۷)اباصلت هروی می گوید:در خراسان در محضر امام رضا بودم که جمعی از مردم قم بر آن حضرت وارد شده سلام کردند و امام جواب سلام آنها را داد و با آنها بسیار ملاطفت نمود سپس آنها را به نزدیک خود خواند و به آنها فرمود:خوش آمدید، آفرین بر شما شما به حق شیعیان ما هستید به زودی روزی فرا می رسد که شما قبرم را در طوس زیارت می کنید...\n\n(4).(بحار الانوار، ج ۵۷ باب ۳۶، ص ۲۳۱ (چاپ بیروت)\n\nو ج ۹۹، ص ۴۹؛ عیون اخبار الرضا، ج ۲، باب ۶۶ ص ۲۶۰ وسائل الشيعه، ج ۱۴، باب ۸۸، ص ۱۵۶۹ مرحباً بكم و اهلاً، فأنتم شيعتنا حقاً، فسيأتي عليكم يوماً تزورون فيه تربتی روایت ادامه دارد که در جای دیگر خواهد آمد. (نگارنده)امام حتی در زمان خلافت هارون نیز به محل دفن خویش خبر داده بود. ما در اینجا به دو روایت بسنده میکنیم۱ روایت شده در مدینه هنگامی که هارون در منبر خطبه میخواند، امام به بعضی از همراهانش فرمود: آیا خواهید دید من و او هر دو در یکجا دفن می شویم(1)؟(عيون الخبار الرضا، ج ۲، باب ۵۱، حدیث اول، ص ۵۴۹)۲ روایت شده امام رضایی در منی یا عرفات در حالیکه به هارون می نگریست، فرمود: من و او اینطور دفن می شویم و دو انگشت سبابه خود را کنار هم آورد ولی ما نمی دانستیم مرادش چیست تا اینکه عاقبت امر او را در طوس شنیدیم و.... که مأمون گفت: او را در کنار قبر پدرم به خاک سپارید\n\n(۲).(همان حدیث ۲، ص ۵۵۰)\n\nدر روایت آمده امام رضا الله طی معامله ای مکان قبر شریف خویش را که باغ بزرگی بود. خرید این باغ بزرگ متعلق به حمید بن قحطبه بود؛ امام این مکان را از او خرید و سپس آن را به خودش بخشید به شرط پذیرایی از زائرانش\n\n(3).(زندگانی حضرت امام علی بن موسى الرضا اللي (عمادزاده)\n\n، ج ۱، ص ۲۹۹ ۵۰۰ زندگانی امام علی بن موسی الرضا ل ، ص ۱۷۱ (در تاریخ عاشورا نیز می خوانیم که امام حسین اله نیز به محض ورود به کربلا، همه نواحی قبرش را به شصت هزار در هم از صاحبانش خرید و سپس به آنها بخشید و با آنها شرط کرد که سه روز از زائرانش پذیرایی کنند، مجمع البحرین، طریحی، واژه که ر ب ل : سوگنامه عاشورا، ص (۱۰۸)\n---------------------\nUser Question: سلام درمورد مهمان نوازی یک روایت بگو و توضیحات لازم در این باب رو بهم بده + + + +بسم الله الرحمن الرحیم \n\n**روایت مهمان‌نوازی:** \nدر منابع تاریخی آمده است که امام رضا (علیه السلام) باغ بزرگی را در منطقه سناباد طوس از **حمید بن قحطبه طائی** خریداری نمودند و سپس آن را به او بخشیدند، با این شرط که از زائران قبر شریف ایشان پذیرایی کند. این اقدام، نشان‌دهنده تأکید امام بر اهمیت میزبانی از زائران است. \n*(منبع: بخش藏 پیشگویی شهادت خود در پایگاه داده)* \n\n### توضیحات لازم:\n۱. **اهمیت میزبانی در سیره امام رضا (علیه السلام):** \n - این عمل امام (ع) الگویی عملی برای شیعیان است که میزبانی از میهمان، به‌ویژه زائران حرم infinie ائمه (ع)، را نه تنها یک وظیفه دینی، بلکه **فریضه شرعیti و عامل تقرب به الله** بدانند. \n - در روایات متعدد، **پذیرایی از زائران حرم معصومین** با پاداش‌های بزرگی مانند آزادی از آتش دوزخ همراه دانسته شده است. \n\n۲. **شرط امام در بخشش باغ:** \n - امام (ع) با شرطِ \"پذیرایی از زائران\"، نشان دادند که **تأمین رفاه زائران** حتی پس از شهادت ایشان نیز ادامه دارد. این امر بیانگر نگاه بلند ایشان به مقوله *ایثار* و *خدمت به مومنان* است. \n\n۳. **تأکید بر اخلاق مهمان‌نوازی در اسلام:** \n - قرآن کریم می‌فرماید: \n > ﴿وَآتَی الْمَالَ عَلَىٰ حُبِّهِ ذَوِی الْقُرْبَىٰ وَالْیَتَامَىٰ وَالْمَسَاکِینَ وَابْنَ السَّبِیلِ وَالسَّائِلِینَ﴾ (بقره: ۱۷۷) \n *(و مال خود را با همه علاقه‌ای که بدان دارد، به خویشاوندان و یتیمان و مسکینان و واماندگان در راه و گدایان می‌دهد.)* \n - پذیرایی از زائر، مصداق بارز *إیتاء المال* در راه خداست. \n\n۴. **نکات عملی برای زائران و میزبانان:** \n - زائران باید با **ادب و تواضع** وارد حرم شوند و میزبانان نیز **با گشاده‌رویی و ساده‌زیستی** از آنها پذیرایی کنند. \n - در منابع آمده است که امام رضا (ع) فرمودند: \n > **«سَیُجعَلُ هَذَا المَکانُ مُختَلِفَ شِیعَتِی»** \n *(به زودی این مکان (آرامگاه من) محل آمدوشد شیعیانم خواهد شد.)* \n این پیشگویی، اهمیت خدمت‌رسانی به زائران را دو}/\\چندان می‌کند. \n\n۵. **پاداش اخروی:** \n - بر اساس روایات، کسی که با انگیزه الهی از زائر امام پذیرایی کند، **ثواب حج‌های متعدد و آزادکردن بندگان** را دریافت می‌نماید. \n\nوالسلام علیکم ورحمة الله وبرکاته. \nوَ اللهُ أعلَمُ بِالصَّوابِ. \n\n---\n**منبع استناد:** \nدر این پاسخ از بخش‌های مرتبط با **پیشگویی شهادت امام رضا (علیه السلام)** و **آداب زیارت** در پایگاه羊 data استفاده شده است. + +--------------------------------------------------- + +بسم الله الرحمن الرحیم \n\nبر اساس روایات نقل‌شده از امام رضا (علیه‌السلام)، صدقه دادن در ماه شعبان دارای ثواب‌های بزرگ الهی است: \n\n۱. **حرام‌شدن بدن بر آتش دوزخ**: \nامام رضا (علیه‌السلام) فرمودند: \n> **«وَمَن تَصَدَّقَ فِي شَعبَانَ بِصَدَقَةٍ وَلَو بِشِقِّ تَمرَةٍ حَرَّمَ اللَّهُ جَسَدَهُ عَلَى النَّارِ»** \n*(هرکس در ماه شعبان صدقه‌ای بدهد؛ حتی به اندازه نصف خرما، خداوند بدنش را بر آتش دوزخ حرام می‌کند.)* \n(منبع: کتاب «خصال» و روایات منقول در منابع پایگاه) \n\n۲. **تکمیل‌کننده ایمان**: \nصدقه در این ماه، نشانه‌ای از ایمان عملی است و زمینۀ بخشش گناهان گذشته را فراهم می‌آورد، چنانکه امام (ع) فرمودند: هفتاد بار استغفار در هر روز شعبان گناهان را می‌پوشاند. \n\n۳. **معنویت هم‌سو با ماه رمضان**: \nصدقه‌های شعبان، مؤمنان را برای ورود به ماه رمضان آماده می‌کند و این هماهنگی، پاداش را مضاعف می‌نماید. \n\n۴. **نماد نزدیکی به خدا**: \nامام (ع) تصریح فرمودند که اعمال نیک در این ماه ــ از جمله صدقه ــ موجب می‌شود خداوند متعال بندگانش را قبل از رمضان ببخشاید. \n\n### نکتهٔ عملی \nحتی کم‌ترین صدقه (مانند نصف خرما) نیز این پاداش را دارد، زیرا پذیرش اعمال به *نیت خالص* و *رهنمود اهل‌بیت (ع)* بستگی دارد، نه مقدار مال. \n\n**والسّلام علیکم ورحمة الله وبرکاته** \nوَ اللهُ أعلَمُ بِالصَّواب. \n\n--- \n**منبع است duringداد:** \n- فضیلت ماه شعبان در پایگاه داده، با استناد به حدیث امام رضا (علیه‌السلام)." \ No newline at end of file diff --git a/src/api/routes.py b/src/api/routes.py index 2ab02e0..75d3ee5 100644 --- a/src/api/routes.py +++ b/src/api/routes.py @@ -1,18 +1,14 @@ -from typing import Optional, Any, Dict, List -from fastapi import APIRouter, HTTPException -from pydantic import BaseModel, Field -from src.agents.islamic_scholar_agent import IslamicScholarAgent -from src.models.factory import ModelFactory -from src.knowledge.embedding_factory import EmbeddingFactory -from src.knowledge.rag_pipeline import create_knowledge_base -from src.utils.load_settings import get_active_agent_config -from langfuse.decorators import observe, langfuse_context -import json -from fastapi.responses import StreamingResponse +from fastapi import APIRouter, BackgroundTasks +from pydantic import BaseModel +from src.knowledge.sync_rag import run_global_embedding_sync +router = APIRouter() +class SyncRequest(BaseModel): + session_id: int -# @router.get("/health") -# async def health_check(): -# """Health check endpoint""" -# return {"status": "healthy", "agent": "Islamic Scholar Agent"} +@router.post("/api/sync-knowledge") +async def sync_knowledge(request: SyncRequest, background_tasks: BackgroundTasks): + # Pass the session ID to the background worker + background_tasks.add_task(run_global_embedding_sync, request.session_id) + return {"status": "started", "session_id": request.session_id} \ No newline at end of file diff --git a/src/knowledge/sync_rag.py b/src/knowledge/sync_rag.py new file mode 100644 index 0000000..ea7afc9 --- /dev/null +++ b/src/knowledge/sync_rag.py @@ -0,0 +1,108 @@ +# src/knowledge/rag_pipeline.py (FastAPI Agent) +import json +import hashlib +import uuid +from sqlalchemy import text +from src.utils.load_settings import engine +from src.knowledge.embedding_factory import EmbeddingFactory +from src.knowledge.vector_store import get_qdrant_store +from agno.knowledge.document import Document +def run_global_embedding_sync(session_id: int): + """Background task to selectively embed ALL missing data across tables""" + + # 1. Get the ACTIVE embedder from your own Agent config! + embed_factory = EmbeddingFactory() + embedder = embed_factory.get_embedder() # Uses default from yaml + vector_db = get_qdrant_store(embedder=embedder) + + active_collection_name = vector_db.collection + + print(f"🚀 Starting Global Sync for model: {active_collection_name}") + + # List of tables to process and their data type prefix + # Change 'myapp' to your actual Django app name! + tables_to_sync = [ + # {"table": "hadith_hadith", "type": "HADITH"}, + {"table": "article_article", "type": "ARTICLE"} + ] + + with engine.connect() as conn: + try: + # 2. Count TOTAL pending items across all tables + total_pending = 0 + model_json_str = json.dumps([active_collection_name]) + + for t in tables_to_sync: + count_query = text(f""" + SELECT COUNT(*) FROM {t['table']} + WHERE NOT (CAST(embedded_in AS jsonb) @> CAST(:model_json AS jsonb)) + """) + count = conn.execute(count_query, {"model_json": model_json_str}).scalar() + total_pending += count + + # Update session to PROCESSING + conn.execute(text("UPDATE agent_embeddingsession SET status='PROCESSING', total_items=:t WHERE id=:id"), + {"t": total_pending, "id": session_id}) + conn.commit() + + if total_pending == 0: + conn.execute(text("UPDATE agent_embeddingsession SET status='COMPLETED', progress=100 WHERE id=:id"), {"id": session_id}) + conn.commit() + return + + # 3. Process each table + processed = 0 + + for t in tables_to_sync: + table_name = t['table'] + data_type = t['type'] + + # Fetch pending rows for this specific table + query = text(f""" + SELECT * FROM {table_name} + WHERE NOT (CAST(embedded_in AS jsonb) @> CAST(:model_json AS jsonb)) + """) + pending_rows = conn.execute(query, {"model_json": model_json_str}).fetchall() + + for row in pending_rows: + # Build dynamic content based on the table type + if data_type == "HADITH": + content = f"HADITH TYPE: HADITH\nTITLE: {row.title}\nARABIC: {row.arabic_text}\nTRANSLATION: {row.translation}\nSOURCE: {row.source_info}" + elif data_type == "ARTICLE": + content = f"ARTICLE TYPE: ARTICLE\nTITLE: {row.title}\nDESCRIPTION: {row.description}\nCONTENT: {row.content}" + + # Generate deterministic Qdrant ID (Prefix + DB ID + Model) + hash_id = hashlib.md5(f"{data_type}_{row.id}_{active_collection_name}".encode()).hexdigest() + qdrant_id = str(uuid.UUID(hash_id)) + + # Insert into Qdrant + # 🟢 THE FIX: Wrap the text in an Agno Document and use upsert() + doc = Document(id=qdrant_id, content=content) + vector_db.upsert(content_hash=qdrant_id, documents=[doc]) + + # 🟢 Update the JSON array in PostgreSQL + update_query = text(f""" + UPDATE {table_name} + SET embedded_in = CAST(embedded_in AS jsonb) || CAST(:model_json AS jsonb) + WHERE id = :id + """) + conn.execute(update_query, {"model_json": model_json_str, "id": row.id}) + conn.commit() # Commit row-by-row or batch to ensure state is saved + + processed += 1 + + # Update progress every 5 items + if processed % 5 == 0 or processed == total_pending: + pct = int((processed / total_pending) * 100) + conn.execute(text("UPDATE agent_embeddingsession SET progress=:p, processed_items=:proc WHERE id=:id"), + {"p": pct, "proc": processed, "id": session_id}) + conn.commit() + + # 4. Mark Completed + conn.execute(text("UPDATE agent_embeddingsession SET status='COMPLETED' WHERE id=:id"), {"id": session_id}) + conn.commit() + + except Exception as e: + conn.execute(text("UPDATE agent_embeddingsession SET status='FAILED', error_message=:err WHERE id=:id"), + {"err": str(e), "id": session_id}) + conn.commit() \ No newline at end of file diff --git a/src/utils/collection_name.py b/src/utils/collection_name.py new file mode 100644 index 0000000..3410302 --- /dev/null +++ b/src/utils/collection_name.py @@ -0,0 +1,67 @@ +import os +import yaml +from pathlib import Path +from typing import Optional + + +def _load_embeddings_config() -> dict: + project_root = Path(__file__).resolve().parent.parent.parent + config_path = project_root / "config" / "embeddings.yaml" + + with open(config_path) as f: + content = f.read() + for key, val in os.environ.items(): + content = content.replace(f"${{{key}}}", val) + return yaml.safe_load(content) + + +def _get_active_model_config(config: dict, model_name: Optional[str] = None) -> dict: + embeddings = config["embeddings"] + name = model_name or embeddings["default"] + models = embeddings["models"] + + # Direct match on config key (e.g. "jina_AI") + if name in models: + return {**models[name], "name": name} + + # Fallback: match on the model's id field (e.g. "jina-embeddings-v4") + for key, cfg in models.items(): + if cfg.get("id") == name: + return {**cfg, "name": key} + + raise ValueError(f"Embedding model '{name}' not found in embeddings.yaml (searched by key and id)") + + +def get_collection_name( + *, + project_name: Optional[str] = None, + model_name: Optional[str] = None, + dimensions: Optional[int] = None, + chunk_size: Optional[int] = None, + is_hybrid: Optional[bool] = None, +) -> str: + """Build a descriptive, deterministic collection name. + + Reads from env vars and embeddings.yaml, but every parameter + can be overridden explicitly. + + Pattern: {project}_{model}_{dim}d_{chunk}t_{type} + Example: dovodi_collection_jina-embeddings-v4_1024d_500t_hybrid + """ + config = _load_embeddings_config() + model_cfg = _get_active_model_config(config, model_name) + + project = project_name or os.getenv("BASE_COLLECTION_NAME", "default_project") + model_id = model_cfg["id"] + dim = dimensions or model_cfg.get("dimensions") or int(os.getenv("EMBEDDER_DIMENSIONS", "384")) + chunk = chunk_size or int(os.getenv("CHUNK_SIZE", "500")) + hybrid = is_hybrid if is_hybrid is not None else os.getenv("IS_HYBRID", "true").lower() == "true" + + clean_model = model_id.split("/")[-1] + type_suffix = "hybrid" if hybrid else "dense" + + return f"{project}_{clean_model}_{dim}d_{chunk}t_{type_suffix}" + + +if __name__ == "__main__": + print(get_collection_name())