# DocSummarizer Part 5 - lucidRAG: MultiM SK3Document RAG वेब अनुप्रयोग

<!--category-- AI, LLM, RAG, C#, HTMX, GraphRAG, Semantic Search, DuckDB -->
<datetime class="hidden">2026-01-01T18:00</datetime>

यह है **भाग 5** DocSummarizer श्रृंखला के ',' और यह''' भी के चरमोत्कर्ष [ग्राफ आर ए जी श्रृङ्खला](/blog/graphrag-minimum-viable-implementation) और [अर्थ खोज श्रृङ्खला](/blog/semantic-search-with-onnx-and-qdrant)हम सब कुछ एक विस्थापित वेब अनुप्रयोग में सम्मिलित कर रहे हैं

> पूर्वावलोकन अनुच्छेद 🚨🚨 अभी भी कुछ kinks का निर्माण कर रहा है और विशेषताओं को जोड़ने के लिए।

> **RAG अवसंरचना का निर्माण करने की पूरी बात यह है कि उसे किसी वास्तविक चीज़ के लिए उपयोग करना।**

पिछले कुछ सप्ताहों के दौरान हम

- **डॉक-सममैरिजर** - दस्तावेज विश्लेषण, अर्थात्मक खंडन
- **ग्राफ आर ए जी** - इकाई निष्कर्षन, ज्ञान ग्राफ्स
- **सेमेंटिक खोज** आरआरएफ संलयन के साथ BERT हाइब्रिड खोज

अब हम उन में एक साथ तार **सुस्पष्टRAG** बहुविध के लिए एक स्टैंडलोन वेब अनुप्रयोग

**वेबसाइट** [lucidrag.com](https://lucidrag.com) | **स्रोत:** [जिटहब](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.RagDocuments)

[TOC]

## lucidRAG क्या करता है

दस्तावेजों को अपलोड करें. प्रश्न पूछें

**प्रमुख विशेषताएँ**

- **बहु--document अपलोड** ड्रॉप के साथ
- **एजेंटिक आरएजी** Query विघटन और स्वयं
- **ज्ञान ग्राफ दृश्यीकरण** - अस्तित्व संबंध देखें
- **साक्ष्य दृश्य** - Sentence-level source citations
- **एकल प्रचालन** - एकल निष्पादनीय या डोकर

**डिजाइन प्रतिबंध**

- अनुक्रमण के लिए कोई क्लाउड निर्भरता नहीं
- निर्णायक पूर्वप्रसंस्करण (चंकन | , | अंतःकरण |, | इकाई निष्कर्षण
- स्रोत दस्तावेजों से पुन: निर्माण योग्य भेक्टर स्थिति
- उपयोग में लाए गए एलएलएम *केवल* प्राप्त साक्ष्य पर उत्तर संश्लेषण के लिए

> किसी भी बिंदु में LLMs chunking के लिए प्रयोग नहीं किया जाता है।

## वेक्टर खोज को क्यों जोड़ें + ज्ञान ग्राफ्स

एकल सदिश खोज कुछ क्वेरी प्रकारों के लिए टूटती है

Query Type
|------------|----------------------|----------------|
| क्रॉस
| Entity-centric | | "Docker के बारे में क्या है?
| वैश्विक सारांश

lucidRAG precision के लिए दोनों सदिशों का उपयोग करता है

## वास्तुकला की समीक्षा

एप्लिकेशन लेयर हम पहले से ही बनाया है तीन परियोजनाओं के लिए-' **[स्टिलियोफ्लो](/blog/styloflow-signal-driven-workflows)** एक सिग्नल

```
lucidRAG
├── Controllers/Api/    # REST endpoints
├── Services/           # Business logic
│   ├── DocumentProcessingService   # Wraps DocSummarizer
│   ├── EntityGraphService          # Wraps GraphRAG
│   └── Background/                 # Async queue processing (StyloFlow waves)
└── Views/              # HTMX + Alpine.js UI
```

**क्यों StyloFlow** हार्डकोड पाइपलाइनों के बजाय प्रत्येक प्रक्रमण चरण एक "वाव्वाव" है जो संकेत जारी करता है। [स्टिलियोफ्लो: सिग्नल](/blog/styloflow-signal-driven-workflows) क्रियान्वयन विवरण के लिए

## प्रसंस्करण पाइपलाइन

जब आप एक दस्तावेज़ अपलोड करते हैं तो यह तीन चरणों के माध्यम से प्रवाहित होता है

### चरण 1: अपलोड और कतार

अपलोड अंतबिंदु फ़ाइल को वैध करता है

```csharp
public async Task<Guid> QueueDocumentAsync(Stream fileStream, string fileName)
{
    // Compute hash to detect duplicates
    var contentHash = ComputeHash(fileStream);

    var existing = await _db.Documents
        .FirstOrDefaultAsync(d => d.ContentHash == contentHash);
    if (existing != null)
        return existing.Id; // Already processed
```

कुंजी अंतर्दृष्टि

```csharp
    // Save to disk, create DB record
    var docId = Guid.NewGuid();
    await SaveFileToDiskAsync(fileStream, docId, fileName);

    // Queue for background processing
    await _queue.EnqueueAsync(new DocumentProcessingJob(docId, filePath));

    return docId;
}
```

### स्टेज 2: सेटिंग और सम्मिलन

पृष्ठभूमि प्रोसेसर लामबद्ध दस्तावेज उठाता है और उन्हें DocSummarizer के माध्यम से चलाता है

```csharp
var result = await _summarizer.SummarizeFileAsync(job.FilePath, progressChannel);
```

यह एकल लाइन बहुत काम करता है [DocSummarizer भाग 1](/blog/building-a-document-summarizer-with-rag)):

- दस्तावेज़ संरचना को पद वर्णन करें (PDF, DOCXM SK2 Markdown )
- शीर्षकों के संबंध में अर्थात्मक टुकड़ों में विभाजित करें
- प्रत्येक टुकड़े के लिए एनएनसी एम्बेडिंग उत्पन्न करें
- HNSW अनुक्रमण के साथ डकडीबी में सदिशों को भंडारित करें

### चरण 3: इकाई निष्कर्षण

chunking के बाद हम GraphRAG का उपयोग कर इकाइयां निकालते हैं

```csharp
var segments = await _vectorStore.GetDocumentSegmentsAsync(documentId);
var entityResult = await _entityGraph.ExtractAndStoreEntitiesAsync(documentId, segments);
```

यह IDF स्कोरिंग और संरचनात्मक संकेतों के बजाय per -chunk LLM कॉल्स का उपयोग करता है [GraphRAG भाग 2](/blog/graphrag-minimum-viable-implementation) विवरण के लिए.

## बैकप्रेस के लिए बार्ड चैनल

एक naiv implementation would use unbounded queues

```csharp
private readonly Channel<DocumentProcessingJob> _queue =
    Channel.CreateBounded<DocumentProcessingJob>(new BoundedChannelOptions(100)
    {
        FullMode = BoundedChannelFullMode.Wait
    });
```

जब कतार भरी जाती है `Wait` मोड खाली स्थान खोलने तक नए लेखन को रोकता है

```csharp
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
timeoutCts.CancelAfter(TimeSpan.FromMinutes(5));

try {
    await _queue.Writer.WriteAsync(job, timeoutCts.Token);
} catch (OperationCanceledException) when (!ct.IsCancellationRequested) {
    throw new InvalidOperationException("Queue full. Try again later.");
}
```

## Per- दस्तावेज़ समय समाप्ति

बड़े दस्तावेजों को प्रक्रिया करने में मिनट लग सकते हैं।

```csharp
while (!stoppingToken.IsCancellationRequested)
{
    var job = await _queue.DequeueAsync(stoppingToken);

    // 30-minute timeout per document
    using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
    timeoutCts.CancelAfter(TimeSpan.FromMinutes(30));

    try {
        await ProcessDocumentAsync(job, timeoutCts.Token);
    } catch (OperationCanceledException) when (!stoppingToken.IsCancellationRequested) {
        await MarkDocumentFailedAsync(job.DocumentId, "Processing timed out");
    }
}
```

लिंक टोकन यह सुनिश्चित करता है कि हम अभी भी अनुप्रयोग बंद करने का सम्मान करते हैं जब पर per जोड़ें

## प्रगति चैनल साफ करें

प्रत्येक प्रक्रमण दस्तावेज को एसईएस अद्यतन के लिए प्रगति चैनल मिलता है।

```csharp
private readonly ConcurrentDictionary<Guid, ProgressChannelEntry> _progressChannels = new();

public int CleanupAbandonedChannels()
{
    var cutoff = DateTimeOffset.UtcNow - TimeSpan.FromHours(1);
    var cleaned = 0;

    foreach (var kvp in _progressChannels.Where(x => x.Value.CreatedAt < cutoff))
    {
        if (_progressChannels.TryRemove(kvp.Key, out var entry))
        {
            entry.Channel.Writer.TryComplete();
            cleaned++;
        }
    }
    return cleaned;
}
```

ए `PeriodicTimer` पृष्ठभूमि प्रोसेसर में हर 15 मिनट यह कॉल करता है

## भंडारण

हम विभिन्न प्रयोजनों के लिए दो डेटाबेस का उपयोग करते हैं

**PostgreSQL/SQLite (EF Core** दस्तावेज़ मेटाडेटा भंडारित करता है - क्या मौजूद है, प्रक्रमण स्थिति

**डक डीबी** सदिशों और अस्तित्व ग्राफ को भंडारित करता है

```csharp
// Metadata in PostgreSQL
public class DocumentEntity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string ContentHash { get; set; }
    public DocumentStatus Status { get; set; }
}

// Vectors in DuckDB (managed by DocSummarizer)
// Entities in DuckDB (managed by GraphRAG)
```

## चैट API

उत्प्रेरक खोज पाइपलाइन के माध्यम से प्रश्न प्रवाहित होते हैं

```csharp
[HttpPost]
public async Task<IActionResult> ChatAsync([FromBody] ChatRequest request)
{
    // 1. Get or create conversation for memory
    var conversation = await GetOrCreateConversationAsync(request.ConversationId);

    // 2. Search with hybrid retrieval
    var searchResult = await _search.SearchAsync(request.Query, new SearchOptions
    {
        TopK = 10,
        IncludeGraphData = request.IncludeGraphData
    });
```

खोज सेवा आवश्यकता पड़ने पर क्वेरी विघटन को नियंत्रित करता है

```csharp
    // 3. Generate answer with LLM
    var answer = await _summarizer.SummarizeAsync(
        request.Query,
        searchResult.Segments,
        new SummarizeOptions { IncludeCitations = true });

    // 4. Save to conversation history
    await SaveToConversationAsync(conversation.Id, request.Query, answer);

    return Ok(new ChatResponse
    {
        Answer = answer.Text,
        Sources = answer.Citations,
        GraphData = searchResult.GraphData
    });
}
```

## UI: HTMX + AlpineM SK2js

यूआई एक एकल पृष्ठ है जिसमें दस्तावेज बाएँ पर हैं

```
┌──────────────────┬─────────────────────────────────────┐
│  📁 Documents    │  💬 Chat                            │
│  ─────────────   │  [Answer] [Evidence] [Graph]       │
│  [+ Upload]      │                                     │
│  📄 api-docs.pdf │  Q: How does auth work?            │
│  📝 readme.md    │  A: JWT tokens stored... [1][2]    │
│  ─────────────   │                                     │
│  🕸️ Graph: 168   │  ┌─────────────────────────────┐   │
│                  │  │ Ask about your documents... │   │
└──────────────────┴──┴─────────────────────────────┴───┘
```

Alpine.js राज्य को प्रबंधित करता है

```javascript
function ragApp() {
    return {
        messages: [],
        isTyping: false,

        async sendMessage() {
            const query = this.currentMessage.trim();
            this.messages.push({ role: 'user', content: query });
            this.isTyping = true;

            const result = await fetch('/api/chat', {
                method: 'POST',
                body: JSON.stringify({ query })
            }).then(r => r.json());

            this.messages.push({
                role: 'assistant',
                content: result.answer,
                sources: result.sources
            });
            this.isTyping = false;
        }
    };
}
```

## डेमो मोड

Lucidrag जैसे सार्वजनिक विनियोजनों के लिए डेमो मोड अक्षम करता है और पूर्व प्रयोग करता है।

```csharp
public class DemoModeConfig
{
    public bool Enabled { get; set; } = false;
    public string ContentPath { get; set; } = "./demo-content";
    public string BannerMessage { get; set; } = "Demo Mode: Pre-loaded RAG articles";
}
```

ए `DemoContentSeeder` पृष्ठभूमि सेवा सामग्री निर्देशिका को देखता है और किसी भी छोड़े गए फ़ाइलों को प्रक्रमित करता है

```csharp
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    if (!_config.DemoMode.Enabled) return;

    await SeedExistingContentAsync();
    StartFileWatcher(_config.DemoMode.ContentPath);
}
```

यह आपको सिर्फ फ़ाइलों को प्रतिलिपि करके डेमो सामग्री अद्यतन करने देता है

## चल रहा lucidRAG

### स्टैंडलोन (नहीं निर्भरताएँ है

```bash
dotnet run --project Mostlylucid.RagDocuments -- --standalone
```

SQLite का उपयोग करता है + DuckDB स्थानीय रूप से. खोलें `http://localhost:5080`.

### डॉकर

```yaml
services:
  lucidrag:
    build: .
    ports: ["5080:8080"]
    depends_on: [postgres, ollama]
```

## क्या वास्तव में चलता है

घटक
|-----------|--------|---------|
दस्तावेज विश्लेषण | DocSummarizer
| ONNX अंतःस्थापित करें | | | DocSummarizer
इकाई निष्कर्षण | ग्राफ आरएग | | | IDF |+ | संरचनात्मक संकेत |
हाइब्रिड खोज
अतुल्य प्रक्रमण
वेब यूआई

### लागत

**शून्य API लागत** अनुक्रमण के लिए - एम्बेडिंग ONNX हैं | , | इकाइयां हेयूरिस्टिक है |. | आप केवल क्वेरी समय पर LLM संश्लेषण का भुगतान करते हैं \ , | और यह स्थानीय ओललामा से काम करता है

## संबंधित लेख

- [DocSummarizer भाग 1 - वास्तुकला](/blog/building-a-document-summarizer-with-rag)
- [DocSummarizer भाग 4 - RAG पाइपलाइन्स](/blog/docsummarizer-rag-pipeline)
- [ग्राफ आर ए जी भाग](/blog/graphrag-minimum-viable-implementation)
- [ऑनिक्स के साथ सेमेटिक खोज](/blog/semantic-search-with-onnx-and-qdrant)