Back to "أنابيب الأوCR المحدودة الغامضة - ثلاثية -Tier"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

AI Architecture Florence-2 LLM OCR Patterns

أنابيب الأوCR المحدودة الغامضة - ثلاثية -Tier

Wednesday, 07 January 2026

جزء 4: استخبارات الصورة قدم معمارية موجات ImageSummarizer ونماذج أوسع نظام فرعي OCR—ثلاثة طوابق من إستخراج النص , توجيه ذكي | , | و تحسين مسار الأفلام الذي يحقق |30× | تخفيض الرموز لGIF الرسوم المتحركة

لماذا مقالة مختلفة? خط أنابيب التصوير بالرنين المغناطيسي تطور من "Tesseract مع Vision LLM fallback" إلى نظام ثلاثي الأبعاد متطور -tier مع MLMSC3based OCRM SK4 multiMST5frame votingMSSK6 textMS-only strip extractionMSR8 and costMSL9aware routingMSV10 ItMSP11s complex enough to warrant its own detailed breakdownMSS12

المقالات المترابطة:


المشكلة: استخراج النص صعب

التصوير بالرنين المغناطيسي على الصور الحقيقية

  • خطوط مصممة: تدرب Tesseract على الخطوط القياسية, يفشل في كتابة الديكورية
  • GIF ضوئية: artefacts of Frame compression , jitter, changes in subtitle
  • وضوح صغير: نص مظلم على خلفية مظلمة
  • تدوير النص: غير- زوايا النص الأفقية
  • المحتوى المزج: لقطة شاشة مع مناطق نصية متعددة
  • تكاليف API: المكالمات لـ Vision LLM مكلفة ($0.001-0.01 لكل صورة

المقاربة التقليدية: "Run Tesseract , إذا فشلت في استخدام Vision LLMM SK3

المشكلة: هذا إما يفتقد النص المصمم ( تفشل تيسيراكت) أو يكلف أكثر من ذلك ( دائماً تستخدم الـ Vision LLM

الحل: أضف مستوى متوسط (FlorenceM SK2 ONNX) يتعامل مع الخطوط المصممة بشكل محليMSC4 يتدرج إلى Vision LLM فقط عندما تفشل كل الطرق المحليةMスク5


العمارة الثلاثية -Tier

يقوم النظام بتشغيل الأمواج في ترتيب أولي (أعلى رقم = تنفيذ متأخر):

Wave Priority Order:
  40: TextLikelinessWave → Heuristic text detection
  50: OcrWave            → Tesseract OCR (if text-likely)
  51: MlOcrWave          → Florence-2 ML OCR (if Tesseract low confidence)
  55: Florence2Wave      → Florence-2 captions (optional)
  80: VisionLlmWave      → Vision LLM (escalation)

الطبقة 1: Tesseract (Traditional OCR)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل мсc4 الحدود psc5 |----------|-------|-------|----------|------------| | 50 | ~50ms | مجانية | نص نقي, إختلاف كبيرM SK5 шрифтات قياسية | | | Schriftات مصممة |, | منخفضة الجودة |

الإشارات المنبعثة:

  • ocr.text - نص تم استخراجه
  • ocr.confidence - نمره الثقة المتوسطة لـ Tesseract

مستوى 2: فلورانسM SK1 أونكس (ML OCR)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل мсc4 الحدود psc5 |----------|-------|-------|----------|------------| | 51 | ~200ms | مجانية | Schriftات مصممةM SK4 الميمات, النص الديكوري MPSK6 الرسوم البيانية المعقدةMPK7 النص المدور PMK8

الإشارات المنبعثة:

  • ocr.ml.text - واحدM SK1 إطار فلورانس-2 رسم بياني
  • ocr.ml.multiframe_text - متعددةM SK1 نص إطار GIF (من المفضلة للانيميشنات)
  • ocr.ml.confidence - نمط درجة الثقة

مستوى 3: Vision LLM (Cloud Fallback)

MSC0 الأولوية MSC1 السرعة msc2 التكلفة msc3 الأفضل ل psc4 القيود scs5

---------- ------- ------- ---------- ------------

الإشارات المنبعثة:

  • ocr.vision.text - إستخراج النص لـ Vision LLM OCR
  • ocr.vision.confidence - الثقة في الـ LLM
  • caption.text - عنوان وصفي إختياري ( منفصل عن الرسم البياني

الـ ONNX Arsenal: نماذج ML محلية

قبل الغوص في ثلاث طبقات من التصوير بالرنين المغناطيسي نماذج ML محددة التي تعمل على النظام. جميع النماذج تعمل محلياً من خلال ONNX Runtime— لا مكالمات APIM SK2 لا إعتمادات السحاب , لا تكاليف

لماذا ONNX?

  • يجري محلياً: لا توجد مفاتيح API, لا يوجد تأخير في الشبكة
  • إختبارية: نفس الدخل = نفس المخرج ( لا أخذ عينات / عشوائية درجة الحرارة )*
  • أسرع:الhardware-accelerated (CPUM SK3GPU≥),إستنتاج مُحسن
  • قابلة للنقل: يعمل على وينډوز
  • أوتومات-لقد تم تحميله: أول عملية تحميل نماذج تلقائيا

* تحذير صغير: مقدمي تنفيذ GPU يمكن أن تضع في الإعتبار اللامحدودية الضئيلة-point nondeterminismM SK2 العقد السلكي (confidence thresholdsMSC4 routing logicMST5 remains fully deterministicMSM6

الخمس نماذج أونكس

ملاحظة: الحجم تقريبية ومتغيرة حسب النموذج/كميّنةM SK2 بحجمات تحميل تقليدية تظهر في الأسفلMSC3

نمط تقريبا. الحجم الهدف السرعة نوع النموذج
الشرق ~100MB الكشف عن النص في المشهد ♫~20ms ♫ ♫ الكشف عن texte ♫
CRAFT ~150MB الرمز-إكتشاف النص في المنطقة ms إختشاف tekst
فلورانس-2 ~250MB نغمة صوتية + تُقَمّر S ~200ms ♫ الرؤية ♫ -لغة ♫
Real-ESRGAN ~60MB
قفص ~600MB បង្កប់ الدلالية ♫~100ms ♫ ♫បង្កប់ متعددة الأشكال ♫

المساحة الكلية للقرص: ~1.0-1.5GB إعتماداً على الطرازات المختارة.


1. EAST: الكشف عن النص المشهدي

كاشف دقيق وفعال للكتابة النصية في المشهد - يجد مناطق نصية في المناظر الطبيعية

// EAST detects text bounding boxes with confidence scores
var result = await textDetector.RunEastDetectionAsync(imagePath);

// Output: List of BoundingBox with coordinates + confidence
// Example: [BoundingBox(x1:50, y1:100, x2:300, y2:150, confidence:0.92)]

كيف تعمل:

  • نموذج التعلم العميق تم تدريبه على مجموعات البيانات النصية في المشهد
  • خريطة النتائج (الثقة) +خريطة هندسية (نقاط الصندوقM SK4
  • يدوي النص المدور, متعددة-النص على مقياس
  • يستخدم غير -مضغوط اعظمي (NMS) لدمج اللوحات المتداخلة

لماذا ديناميكية?

  • لا عشوائية في الاستنتاج (كثافات متجمدة)
  • نفس الصورة → نفس الصناديق المزدوجة
  • نقاط الثقة قابلة للتكرار
  • حد الهبوط هو config-driven M SK1e.gMSC3 < 0.5 → escalate)

التفاصيل التقنية:

// EAST preprocessing (from implementation)
- Input size: 320×320 (must be multiple of 32)
- Format: BGR with mean subtraction [123.68, 116.78, 103.94]
- Output stride: 4 (downsampled 4×)
- Score threshold: 0.5
- NMS IoU threshold: 0.4

مخرج مثالي:

Input: meme.png (800×600)
EAST detection: 15 text regions found
  Region 1: (50, 480, 750, 580) - confidence 0.87 [bottom subtitle area]
  Region 2: (100, 50, 300, 90) - confidence 0.62 [top text]
  Region 3: ...
Route decision: ANIMATED (subtitle pattern in bottom 30%)

2. CRAFT: نوع المنطقة الوعي

Character-الكشف عن مستوى النص - يتفوق على الرسم المنحنيM SK1 الفني , والكتابة الملونة.

// CRAFT finds character-level regions, then groups into words
var result = await textDetector.RunCraftDetectionAsync(imagePath);

// Better than EAST for: decorative fonts, curved text, logos

كيف تعمل:

  • يكشف مناطق الخصائص الفردية ( أكثر رقاقة من الشرق الاوسط)
  • يستخدم تقييم الffinity لجمع الشخصيات في كلمات
  • خوارزميا " Flood-fill" تكتشف مكونات نصية متصلة
  • يتعامل مع النص المنحني الذي يفتقده شرق

عندما يتم استخدام "CRAFT":

  1. EAST غير متوفر أو فشل
  2. الصورة تحتوي على أحرف فنية/زينة M SK1إتجاه آلي-محصولةMSC3
  3. يختار المستخدم بوضوح كاشف CRAFT

التفاصيل التقنية:

// CRAFT preprocessing
- Max dimension: 1280px (maintains aspect ratio)
- Format: RGB normalized with ImageNet stats
- Mean: [0.485, 0.456, 0.406]
- Std: [0.229, 0.224, 0.225]
- Output stride: 2 (downsampled 2×)
- Threshold: 0.4 for character regions

اقصى الشرق مقابل CRAFT مقارنة:

الميزة شرق كرات S
مستوى إكتشاف كلمة/خط حرف
السرعة MSC2ms MSC3 \MSC4ms
الأفضل لـ
النص المنحني محدود ممتاز S
حجم النماذج MSC2MB MSC3 150 MB MSC5

3. حقيقي -ESRGAN: سوبرM SK3 رفع الدقة

تحسن الصور ذات الجودة المنخفضة - قبل التصوير بالرسوم المتحركة - 4× رفع الخطوط المضيئةM SK2 نص صغير.

// Upscale low-quality image before running OCR
if (quality.Sharpness < 30)  // Laplacian variance threshold
{
    var upscaled = await esrganService.UpscaleAsync(imagePath, scale: 4);
    // Now run OCR on the enhanced image
}

عندما يتم استخدامه:

  • سماكة الصورة < 30 | | ( | إختلاف لابلاشي
  • لقد تم اكتشاف مناطق نصية لكنها صغيرة جداً (< 20 ارتفاعpx)
  • نسبة الثقة في الخطوط الاصطناعية ضعيفة ولكن مناطق النص موجودة
  • يطلب المستخدم بوضوح التسارع

مثال:

Input:  100×75 screenshot with tiny text
        Laplacian variance: 18 (very blurry)

ESRGAN: Upscale to 400×300 (~500ms)
        New Laplacian variance: 87 (sharp)

OCR:    Tesseract confidence: 0.92 (vs 0.42 before upscaling)
        Text: "Click here to continue" (vs garbled before)

التفاصيل التقنية:

// Real-ESRGAN processing
- Input: Any size (processed in 128×128 tiles if large)
- Output: 4× scaled (200×150 → 800×600)
- Model: x4plus variant (general photos)
- Processing: ~500ms for 800×600 image
- Memory: ~2GB peak (tiles reduce this)

الإقتصاد الرمزي:

Scenario: Screenshot with tiny text

Option 1: Send low-res to Vision LLM
  Image: 100×75 = ~20 tokens
  LLM can't read tiny text → fails
  Cost: $0.0002 (wasted)

Option 2: Upscale with ESRGAN, use Tesseract
  ESRGAN: Free (local), 500ms
  Tesseract: Free (local), 50ms
  Success: 92% confidence
  Cost: $0

Result: ESRGAN + local OCR beats Vision LLM for low-res images

4. CLIP: ملحقات سيمانسية

دمجات متعددة الأشكال لبحث الصور الدلالية - يعرض الصور والكتابة في الفضاء الفيكتوري المشترك

// Generate embedding for semantic search
var embedding = await clipService.GenerateEmbeddingAsync(imagePath);
// Returns: float[512] vector

// Later: semantic search across thousands of images
var similarImages = await vectorDb.SearchAsync(queryEmbedding, topK: 10);

كيف تعمل:

  • CLIP ViT-B/32 برمجة بصرية (350MBM SK3
  • يعرض الصور إلى 512- векторات بعدية
  • تم تدريبهم على التوافق مع الوصفات النصية
  • يُمكن " العثور على صور كهذه" بدون كلمات مرور

إستخدام الحالات:

  • بحث الصور الدلالية في أنظمة RAG
  • إكتشاف مزيف (حتى إذا تم تعديله/مقطعةM SK2
  • Content-based clustering
  • توصيات صور مماثلة

التفاصيل التقنية:

// CLIP visual encoder
- Model: ViT-B/32 (Vision Transformer)
- Input: 224×224 RGB (center crop + resize)
- Output: 512-dimensional embedding
- Normalized: L2 norm = 1.0
- Speed: ~100ms per image

مثال:

Input images:
  cat_on_couch.jpg → [0.23, -0.51, 0.88, ...]
  dog_on_couch.jpg → [0.19, -0.48, 0.91, ...]
  car_photo.jpg    → [-0.67, 0.33, -0.12, ...]

Query: "animals on furniture"
  Text embedding → [0.21, -0.50, 0.89, ...]

Cosine similarity:
  cat_on_couch: 0.94 (very similar!)
  dog_on_couch: 0.91 (similar)
  car_photo: 0.12 (not similar)

Result: Returns cat and dog images

5. فلورانسM SK1 الرؤية-نموذج اللغة (مغطى في الطبقة МSK4

رؤية قسم 2 للتفصيلات الكاملة عن فلورانس-2 ONNX OCR و اللوحاتM SK2


اتومات-نظام تحميل

جميع النماذج يتم تحميلها تلقائياً عند الاستخدام الأول:

$ imagesummarizer image.png --pipeline auto

[First run]
Downloading EAST scene text detector (~100MB)...
  Progress: ████████████████████ 100% (102.4 MB)
Downloading Florence-2 base model (~250MB)...
  Progress: ████████████████████ 100% (248.7 MB)
Downloading CLIP ViT-B/32 visual (~350MB)...
  Progress: ████████████████████ 100% (347.2 MB)

Models saved to: ~/.mostlylucid/models/
Total disk space: 1.16 GB

[Subsequent runs]
All models cached, analysis starts immediately

الانهيار اللطيف:

// If ONNX model download fails, system falls back gracefully
EAST unavailable → Try CRAFT → Fall back to Tesseract PSM
Real-ESRGAN unavailable → Skip upscaling, use original image
CLIP unavailable → Skip embeddings, OCR still works
Florence-2 unavailable → Use Tesseract → Vision LLM escalation

كل فشل نموذج أونكس يتم تسجيله مع طريق التراجع , متأكداً من أن النظام لن يتعطل أبداً بسبب النماذج المفقودة .


لماذا هذا مهم

ملاحظة الأسعار: أمثلة من التكلفة في الأسفل تستخدم رسماً لتسعير (~$0.005/ صورة لـ Vision LLM). تكاليف API الحقيقية تختلف حسب المورد والنموذجM SK3 الإدراك الأساسيMSC4 معالجة محلية تقضي على معظم مكالمات API

بدون نماذج أونكس (خط الأساس):

Every image → Send to Vision LLM
  Cost: ~$0.005/image (example pricing)
  Time: ~2s network + inference
  100 images = ~$0.50, ~200s

مع نماذج ONNX (localM SK1first):

85 images → EAST + Florence-2 (local)
  Cost: $0
  Time: ~200ms

10 images → EAST + Tesseract (local)
  Cost: $0
  Time: ~50ms

5 images → EAST + Vision LLM (escalation)
  Cost: ~$0.025 (5 × $0.005)
  Time: ~2s each

100 images = ~$0.025, ~30s total

الإدخار: ~95% تخفيض من التكلفة, |~85% أسرعM SK4 التوجيه الإفتراضي.

نماذج ONNX تحول النظام من "probabilistic down all the way down" to "deterministic foundation + probabilistic escalation only when neededM SK4


مستوى 1: Tesseract OCR

الخط الاساسي. سريع, محددM SK2 يعمل بشكل جيد للكتابة النظيفة .

public class OcrWave : IAnalysisWave
{
    public string Name => "OcrWave";
    public int Priority => 60;  // After color/identity

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Get preprocessed image from cache
        var image = context.GetCached<Image<Rgba32>>("image");

        // Run Tesseract OCR
        using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
        using var page = engine.Process(image);

        var text = page.GetText();
        var confidence = page.GetMeanConfidence();

        signals.Add(new Signal
        {
            Key = "ocr.text",  // Tesseract OCR result
            Value = text,
            Confidence = confidence,
            Source = Name,
            Tags = new List<string> { "ocr", "text" },
            Metadata = new Dictionary<string, object>
            {
                ["engine"] = "tesseract",
                ["mean_confidence"] = confidence,
                ["word_count"] = text.Split(' ').Length
            }
        });

        signals.Add(new Signal
        {
            Key = "ocr.confidence",
            Value = confidence,
            Confidence = 1.0,
            Source = Name
        });

        return signals;
    }
}

إشارات مفاتيح:

  • ocr.full_text - النص المستخرج
  • ocr.early_exit - إشارة لتخطى مستوى 2/3 إذا كان الثقة مرتفعة
  • تقييم الثقة يقود قرارات التدرج

الطبقة 2: فلورانس-2NX

مايكروسوفت's فلورانس-2 هو نموذج لرؤية - النموذج اللغوي الذي يتفوق على بكتابة كثافة و OCRM SK3 نسخة ONNX تعمل محلياً بدون أي تكاليف API .

لماذا فلورانس-2?

  • أفضل من Tesseract لخطوط مصممة: يدوي النص الزخرف, الميماتM SK2 شعارات
  • أسرع من Vision LLM: ~200ms vs 1-5s
  • مجانية: يشتغل محليا, لا تحتاج إلى مفاتيح API
  • فهم متعدد الأشكال: يمكن استخراج النص في السياق (e.gMSC3 حباب الكلامM SK4

التنفيذ

public class MlOcrWave : IAnalysisWave
{
    private readonly Florence2OnnxModel _model;

    public string Name => "MlOcrWave";
    public int Priority => 51;  // Runs AFTER Tesseract (priority 50)

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Check if Tesseract already succeeded with high confidence
        var tesseractConfidence = context.GetValue<double>("ocr.confidence");
        if (tesseractConfidence >= 0.95)
        {
            signals.Add(new Signal
            {
                Key = "ocr.ml.skipped",  // Consistent namespace: ocr.ml.*
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "tesseract_high_confidence",
                    ["tesseract_confidence"] = tesseractConfidence
                }
            });
            return signals;
        }

        // Run Florence-2 OCR
        var result = await _model.ExtractTextAsync(imagePath, ct);

        signals.Add(new Signal
        {
            Key = "ocr.ml.text",  // Florence-2 ML OCR text
            Value = result.Text,
            Confidence = result.Confidence,
            Source = Name,
            Tags = new List<string> { "ocr", "text", "ml" },
            Metadata = new Dictionary<string, object>
            {
                ["model"] = "florence2-base",
                ["inference_time_ms"] = result.InferenceTime,
                ["token_count"] = result.TokenCount
            }
        });

        // For animated GIFs, extract all unique frames
        if (context.GetValue<int>("identity.frame_count") > 1)
        {
            var frameResults = await ExtractMultiFrameTextAsync(
                imagePath,
                maxFrames: 10,
                ct);

            signals.Add(new Signal
            {
                Key = "ocr.ml.multiframe_text",
                Value = frameResults.CombinedText,
                Confidence = frameResults.AverageConfidence,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["frames_processed"] = frameResults.FrameCount,
                    ["unique_text_segments"] = frameResults.UniqueSegments,
                    ["deduplication_method"] = "levenshtein_85"
                }
            });
        }

        return signals;
    }
}

معالجة GIFFrame متعددة

بالنسبة للGIF المتحركة , فلورانس-2 العمليات إلى 10 الأجزاء المستخرجة بشكل متوازن

private async Task<MultiFrameResult> ExtractMultiFrameTextAsync(
    string imagePath,
    int maxFrames,
    CancellationToken ct)
{
    // Load GIF and extract frames
    using var image = await Image.LoadAsync<Rgba32>(imagePath, ct);
    var frames = new List<Image<Rgba32>>();

    int frameCount = image.Frames.Count;
    int step = Math.Max(1, frameCount / maxFrames);

    for (int i = 0; i < frameCount; i += step)
    {
        frames.Add(image.Frames.CloneFrame(i));
    }

    // Process all frames in parallel (bounded concurrency to avoid thrashing)
    var semaphore = new SemaphoreSlim(4);  // Max 4 concurrent inferences
    var tasks = frames.Select(async frame =>
    {
        await semaphore.WaitAsync(ct);
        try
        {
            var result = await _model.ExtractTextAsync(frame, ct);
            return result;
        }
        finally
        {
            semaphore.Release();
        }
    });

    var results = await Task.WhenAll(tasks);
    semaphore.Dispose();

    // Deduplicate using Levenshtein distance
    var uniqueTexts = DeduplicateByLevenshtein(
        results.Select(r => r.Text).ToList(),
        threshold: 0.85);

    return new MultiFrameResult
    {
        CombinedText = string.Join("\n", uniqueTexts),
        FrameCount = frames.Count,
        UniqueSegments = uniqueTexts.Count,
        AverageConfidence = results.Average(r => r.Confidence)
    };
}

private List<string> DeduplicateByLevenshtein(
    List<string> texts,
    double threshold)
{
    var unique = new List<string>();

    foreach (var text in texts)
    {
        bool isDuplicate = false;
        foreach (var existing in unique)
        {
            var distance = LevenshteinDistance(text, existing);
            var maxLen = Math.Max(text.Length, existing.Length);
            var similarity = 1.0 - (distance / (double)maxLen);

            if (similarity >= threshold)
            {
                isDuplicate = true;
                break;
            }
        }

        if (!isDuplicate)
        {
            unique.Add(text);
        }
    }

    return unique;
}

مثال: 93-صورة GIF | | → |10 | फ्रेमات العينة |

Frame 1-45:  "I'm not even mad."
Frame 46-93: "That's amazing."

إتخاذ القرار في المسار

إكتشاف النص OpenCV (~5-20ms) يحدد أي مسار يجب أخذه

public class TextDetectionService
{
    public TextDetectionResult DetectText(Image<Rgba32> image)
    {
        // Use OpenCV EAST text detector
        var (regions, confidence) = RunEastDetector(image);

        return new TextDetectionResult
        {
            HasText = regions.Count > 0,
            RegionCount = regions.Count,
            Confidence = confidence,
            Route = SelectRoute(regions, confidence, image)
        };
    }

    private ProcessingRoute SelectRoute(
        List<TextRegion> regions,
        double confidence,
        Image<Rgba32> image)
    {
        // No text detected
        if (regions.Count == 0)
            return ProcessingRoute.NoOcr;

        // Animated GIF with subtitle pattern
        if (image.Frames.Count > 1 && HasSubtitlePattern(regions))
            return ProcessingRoute.AnimatedFilmstrip;

        // High confidence, standard text
        if (confidence >= 0.8 && HasStandardTextCharacteristics(regions))
            return ProcessingRoute.Fast;  // Florence-2 only

        // Moderate confidence
        if (confidence >= 0.5)
            return ProcessingRoute.Balanced;  // Florence-2 + Tesseract voting

        // Low confidence, complex image
        return ProcessingRoute.Quality;  // Full pipeline + Vision LLM
    }

    private bool HasSubtitlePattern(List<TextRegion> regions)
    {
        // Subtitles are typically in bottom 30% of frame
        var bottomRegions = regions.Where(r =>
            r.BoundingBox.Y > r.ImageHeight * 0.7);

        return bottomRegions.Count() >= regions.Count * 0.5;
    }
}

أداء الطريق

الطريق يحدد متى المعالجة الوقت التكلفة
أسرع ثقة عالية (>0.8), نص معياري MSC2 فلورانسMSc3 فقط MSC4 МСC5ms msC6 مجانية msC7
متوازن الثقة المتواضعة (0.5-0.8) فلورانس-2 ♫+ التصويت Tesseract 5 6 7 مجاني 8
الجودة ثقة ضعيفة (<0.5), معقدة متعددة - إطار + رؤية اللوحة اللاسلكية ~1-5 $0.001-0.01
تم تصويره GIF مع نمط عنوان فرعي النص-شريحة فيلمية فقط

النص-فقط استخراج الشريط

تحسين التطور لترجمات GIF فقط المناطق النصية, لا إطارات كاملة.

المشكلة

المقاربة التقليدية لـ 93-frame GIF with subtitles

Option 1: Process every frame
  93 frames × 300×185 × ~150 tokens/frame = 13,950 tokens
  Cost: ~$0.14 @ $0.01/1K tokens
  Time: ~27 seconds

Option 2: Sample 10 frames
  10 frames × 300×185 × ~150 tokens/frame = 1,500 tokens
  Cost: ~$0.015
  Time: ~3 seconds
  Problem: Might miss subtitle changes

الحل: النص-فقط الخطوط

استخرج فقط مربعات الكتابة النصية, إزالة पिكسल्स الخلفية :

2 text regions × 250×50 × ~25 tokens/region = 50 tokens
Cost: ~$0.0005
Time: ~2 seconds
Token reduction: 30×

التنفيذ

public class FilmstripService
{
    public async Task<TextOnlyStrip> CreateTextOnlyStripAsync(
        string imagePath,
        CancellationToken ct)
    {
        using var gif = await Image.LoadAsync<Rgba32>(imagePath, ct);

        // 1. Detect subtitle region (bottom 30% of frames)
        var subtitleRegion = DetectSubtitleRegion(gif);

        // 2. Extract frames with text changes
        var uniqueFrames = ExtractUniqueTextFrames(gif, subtitleRegion);

        // 3. Extract tight bounding boxes around text
        var textRegions = ExtractTextBoundingBoxes(uniqueFrames);

        // 4. Create horizontal strip of text-only regions
        var strip = CreateHorizontalStrip(textRegions);

        return new TextOnlyStrip
        {
            Image = strip,
            RegionCount = textRegions.Count,
            TotalTokens = EstimateTokens(strip),
            OriginalTokens = EstimateTokens(gif),
            Reduction = CalculateReduction(strip, gif)
        };
    }

    private Rectangle DetectSubtitleRegion(Image<Rgba32> gif)
    {
        // Analyze bottom 30% of frame for text patterns
        int subtitleHeight = (int)(gif.Height * 0.3);
        int subtitleY = gif.Height - subtitleHeight;

        return new Rectangle(0, subtitleY, gif.Width, subtitleHeight);
    }

    private List<Image<Rgba32>> ExtractUniqueTextFrames(
        Image<Rgba32> gif,
        Rectangle subtitleRegion)
    {
        var uniqueFrames = new List<Image<Rgba32>>();
        Image<Rgba32>? previousFrame = null;

        for (int i = 0; i < gif.Frames.Count; i++)
        {
            var frame = gif.Frames.CloneFrame(i);
            var subtitleCrop = frame.Clone(ctx =>
                ctx.Crop(subtitleRegion));

            // Compare with previous frame
            if (previousFrame == null ||
                HasTextChanged(subtitleCrop, previousFrame, threshold: 0.05))
            {
                uniqueFrames.Add(subtitleCrop);
                previousFrame = subtitleCrop;
            }
        }

        return uniqueFrames;
    }

    private bool HasTextChanged(
        Image<Rgba32> current,
        Image<Rgba32> previous,
        double threshold)
    {
        // Threshold bright pixels (white/yellow text on dark background)
        var currentBright = CountBrightPixels(current);
        var previousBright = CountBrightPixels(previous);

        // Calculate Jaccard similarity of bright pixels
        var intersection = currentBright.Intersect(previousBright).Count();
        var union = currentBright.Union(previousBright).Count();

        var similarity = union > 0 ? intersection / (double)union : 1.0;

        // Text changed if similarity drops below threshold
        return similarity < (1.0 - threshold);
    }

    // Helper type for bounding box + crop
    private record TextCrop
    {
        public required Image<Rgba32> CroppedImage { get; init; }
        public required Rectangle Bounds { get; init; }
    }

    private List<TextCrop> ExtractTextBoundingBoxes(
        List<Image<Rgba32>> frames)
    {
        var textCrops = new List<TextCrop>();

        foreach (var frame in frames)
        {
            // Threshold to get text mask
            var mask = ThresholdBrightPixels(frame, minValue: 200);

            // Find connected components (text regions)
            var components = FindConnectedComponents(mask);

            // Get tight bounding box around all components
            var bbox = GetTightBoundingBox(components);

            // Add padding
            bbox.Inflate(5, 5);

            // Clone the region (dispose properly in production!)
            var cropped = frame.Clone(ctx => ctx.Crop(bbox));

            textCrops.Add(new TextCrop
            {
                CroppedImage = cropped,
                Bounds = bbox
            });
        }

        return textCrops;
    }

    private Image<Rgba32> CreateHorizontalStrip(
        List<TextCrop> textCrops)
    {
        // Calculate strip dimensions
        int totalWidth = textCrops.Sum(c => c.Bounds.Width);
        int maxHeight = textCrops.Max(c => c.Bounds.Height);

        // Create blank canvas
        var strip = new Image<Rgba32>(totalWidth, maxHeight);

        // Paste text regions horizontally
        int xOffset = 0;
        foreach (var crop in textCrops)
        {
            strip.Mutate(ctx => ctx.DrawImage(
                crop.CroppedImage,
                new Point(xOffset, 0),
                opacity: 1.0f));

            xOffset += crop.Bounds.Width;

            // Dispose crop after use (important!)
            crop.CroppedImage.Dispose();
        }

        return strip;
    }
}

مثال بصري

الدخل: anchorman-not-even-mad.gif (93 frames, 300×185)

المعالجة:

1. Detect subtitle region: bottom 30% (300×55)
2. Extract unique frames: 93 frames → 2 text changes
3. Extract tight bounding boxes:
   - Frame 1-45: "I'm not even mad." → 252×49 bbox
   - Frame 46-93: "That's amazing." → 198×49 bbox
4. Create horizontal strip: 450×49 total

ناتج: النص-شريحة واحدة فقط (450×49)

النص-مجرد شريط فقط مثال

إقتصاد الرموز:

  • الإطارات الكاملة (10 تم أخذ عينة): 300×185 | | × |
  • شريط الـ OCR (2 إطارات): 300×185 | | × ♫ |2 ♫
  • النص-شريحة واحدة فقطنغمات : 450×49 | | = |

30× تقليل بينما يحفظ كل نص الترجمة


مستوى 3: رؤية LLM التسارع

عندما تفشل تيسيراكت و فلورانس-2 أو تنتج نتائج ضعيفة-نتائج الثقةM SK2 تتدرج إلى Vision LLM MSC3GPT -4oMスク5 Claude MSSK6 SonnetMSL7 Gemini Pro VisionMST8 أو نماذج أولاما مثل minicpmMSSK9vMS).

بوابة الجودة

public class OcrQualityWave : IAnalysisWave
{
    private readonly SpellChecker _spellChecker;

    public string Name => "OcrQualityWave";
    public int Priority => 58;  // After Florence-2 and Tesseract

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Get best OCR result from earlier waves (priority order)
        string? ocrText =
            context.GetValue<string>("ocr.ml.text") ??  // Florence-2 (priority 51)
            context.GetValue<string>("ocr.text");        // Tesseract (priority 50)

        if (string.IsNullOrWhiteSpace(ocrText))
        {
            signals.Add(new Signal
            {
                Key = "ocr.quality.no_text",
                Value = true,
                Confidence = 1.0,
                Source = Name
            });
            return signals;
        }

        // Run spell check (deterministic quality assessment)
        var spellResult = _spellChecker.CheckTextQuality(ocrText);

        // Additional quality signals to avoid false positives
        var alphanumRatio = CalculateAlphanumericRatio(ocrText);  // Letters/digits vs junk
        var avgTokenLength = CalculateAverageTokenLength(ocrText);

        signals.Add(new Signal
        {
            Key = "ocr.quality.spell_check_score",
            Value = spellResult.CorrectWordsRatio,
            Confidence = 1.0,
            Source = Name,
            Metadata = new Dictionary<string, object>
            {
                ["total_words"] = spellResult.TotalWords,
                ["correct_words"] = spellResult.CorrectWords,
                ["garbled_words"] = spellResult.GarbledWords,
                ["alphanum_ratio"] = alphanumRatio,
                ["avg_token_length"] = avgTokenLength
            }
        });

        // Deterministic escalation threshold
        // NOTE: Spellcheck alone can false-trigger on proper nouns, memes, brand names.
        // Use additional signals (alphanum ratio, token length) to reduce false escalations.
        bool isGarbled = spellResult.CorrectWordsRatio < 0.5 &&
                         alphanumRatio > 0.7;  // Mostly valid characters, just not in dictionary

        signals.Add(new Signal
        {
            Key = "ocr.quality.is_garbled",
          Value = isGarbled,
            Confidence = 1.0,
            Source = Name
        });

        // Signal Vision LLM escalation
        if (isGarbled)
        {
            signals.Add(new Signal
            {
                Key = "ocr.quality.escalation_required",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Tags = new List<string> { "action_required", "escalation" },
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "spell_check_below_threshold",
                    ["quality_score"] = spellResult.CorrectWordsRatio,
                    ["threshold"] = 0.5,
                    ["target_tier"] = "vision_llm"
                }
            });

            // Cache garbled text for Vision LLM to access
            context.SetCached("ocr.garbled_text", ocrText);
        }

        return signals;
    }
}

التسارع هو محدد: علامة إختبار اللغز < 50% | | → تتصاعد. لا الحكم الإحتمالي

Vision LLM مع Filmstrip

عندما يتم تحفيز التسارع للGIF المتحركة , إستخدم النص - فقط الشريط МSK2

public class VisionLlmWave : IAnalysisWave
{
    private readonly IVisionLlmClient _client;

    public string Name => "VisionLlmWave";
    public int Priority => 50;

    public async Task<IEnumerable<Signal>> AnalyzeAsync(
        string imagePath,
        AnalysisContext context,
        CancellationToken ct)
    {
        var signals = new List<Signal>();

        // Check if escalation is required
        var escalationRequired = context.GetValue<bool>(
            "ocr.quality.escalation_required");

        if (!escalationRequired)
        {
            signals.Add(new Signal
            {
                Key = "vision.llm.skipped",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["reason"] = "no_escalation_required"
                }
            });
            return signals;
        }

        // For animated GIFs, use text-only strip
        string imageToProcess = imagePath;
        bool usedFilmstrip = false;

        if (context.GetValue<int>("identity.frame_count") > 1)
        {
            var filmstrip = await CreateTextOnlyStripAsync(imagePath, ct);
            imageToProcess = filmstrip.Path;
            usedFilmstrip = true;

            signals.Add(new Signal
            {
                Key = "vision.filmstrip.created",
                Value = true,
                Confidence = 1.0,
                Source = Name,
                Metadata = new Dictionary<string, object>
                {
                    ["mode"] = "text_only",
                    ["region_count"] = filmstrip.RegionCount,
                    ["token_reduction"] = filmstrip.Reduction,
                    ["original_tokens"] = filmstrip.OriginalTokens,
                    ["final_tokens"] = filmstrip.TotalTokens
                }
            });
        }

        // Build constrained prompt
        var prompt = BuildConstrainedPrompt(context);

        // Call Vision LLM
        var result = await _client.ExtractTextAsync(
            imageToProcess,
            prompt,
            ct);

        // Emit OCR text signal (Vision LLM tier)
        signals.Add(new Signal
        {
            Key = "ocr.vision.text",  // Vision LLM OCR result
            Value = result.Text,
            Confidence = 0.95,  // High but not 1.0 - still probabilistic
            Source = Name,
            Tags = new List<string> { "ocr", "vision", "llm" },
            Metadata = new Dictionary<string, object>
            {
                ["model"] = result.Model,
                ["used_filmstrip"] = usedFilmstrip,
                ["inference_time_ms"] = result.InferenceTime,
                ["token_count"] = result.TokenCount,
                ["cost_usd"] = result.Cost
            }
        });

        // Optionally emit caption if requested (separate from OCR)
        if (result.Caption != null)
        {
            signals.Add(new Signal
            {
                Key = "caption.text",  // Descriptive caption, not OCR
                Value = result.Caption,
                Confidence = 0.90,
                Source = Name,
                Tags = new List<string> { "caption", "description" }
            });
        }

        return signals;
    }

    private string BuildConstrainedPrompt(AnalysisContext context)
    {
        var sb = new StringBuilder();

        sb.AppendLine("Extract all text from this image.");
        sb.AppendLine();
        sb.AppendLine("CONSTRAINTS:");
        sb.AppendLine("- Only extract text that is actually visible");
        sb.AppendLine("- Preserve formatting and line breaks");
        sb.AppendLine("- If no text is present, return empty string");
        sb.AppendLine();

        // Add context from earlier waves
        var garbledText = context.GetCached<string>("ocr.garbled_text");
        if (!string.IsNullOrEmpty(garbledText))
        {
            sb.AppendLine("CONTEXT:");
            sb.AppendLine("Traditional OCR detected garbled text:");
            sb.AppendLine($"  \"{garbledText}\"");
            sb.AppendLine("Use this as a hint for stylized or unusual fonts.");
            sb.AppendLine();
        }

        sb.AppendLine("Return only the extracted text, no commentary.");

        return sb.ToString();
    }
}

السلسلة الأولية

عندما تنتهي جميع الطبقات, يستعمل اختيار النص النهائي ترتيب أولوية صارمة:

public static string? GetFinalText(DynamicImageProfile profile)
{
    // Priority chain (highest to lowest quality)
    // NOTE: This selects ONE source, but the ledger exposes ALL sources
    // with confidence scores for downstream inspection

    // 1. Vision LLM OCR (best for complex/garbled text)
    var visionText = profile.GetValue<string>("ocr.vision.text");
    if (!string.IsNullOrEmpty(visionText))
        return visionText;

    // 2. Florence-2 multi-frame GIF OCR (best for animations)
    var florenceMultiText = profile.GetValue<string>("ocr.ml.multiframe_text");
    if (!string.IsNullOrEmpty(florenceMultiText))
        return florenceMultiText;

    // 3. Florence-2 single-frame ML OCR (good for stylized fonts)
    var florenceText = profile.GetValue<string>("ocr.ml.text");
    if (!string.IsNullOrEmpty(florenceText))
        return florenceText;

    // 4. Tesseract OCR (reliable for clean standard text)
    var tesseractText = profile.GetValue<string>("ocr.text");
    if (!string.IsNullOrEmpty(tesseractText))
        return tesseractText;

    // 5. Fallback (empty)
    return string.Empty;
}

كل مستوى لديه خصائص معروفة:

المصدر مفاتيح الإشارات الأفضل لـ الثقة التكلفة السرعة psk6
Vision LLM OCR ocr.vision.text الرسوم البيانية المعقدةM SK1 النص المدور, مشوهة 0.95 ♫ $0.001-0.01
فلورانسM SK1 (GIF) ocr.ml.multiframe_text الرسوم المتحركة الGIFs مع الأشرطة الفرعية 0.85-0.92
فلورانسM SK1 (single) ocr.ml.text Schriftات مصممة, الميماتM SK2 النص الديكوري 0.85-0.90 | مجاني ~200ms
Tesseract ocr.text نص معياري نقي, متباينة عالية إختلافات MSC3 مجانية MSC4 MSC5 ms

تحليل التكاليف

قبل System Three-Tier

100 الصور, جميعها باستخدام Vision LLM

100 images × $0.005/image = $0.50
Total time: 100 × 2s = 200 seconds

بعد ثلاثة -نظام صور

توزيع الخطوط (نموذجي):

  • 60 صور → الطريق السريع ( فلورانس-2 فقطMSC4 مجانيةMSc5 MSC6ms MSc7
  • 25 صور → طريق متوازن ( فلورانس-2 + تيسيراكتMSк5 مجانيةMSC6 \MSC7msMSc8
  • 10 صور → طريق الجودة (+ رؤية LLM, $0.005, ♫~2sM SK6
  • 5 الصور → الطريق المحصور (مسار الأفلامMSC3 MSC4 | | 5 | 6
Cost:
  60 × $0 = $0
  25 × $0 = $0
  10 × $0.005 = $0.05
  5 × $0.002 = $0.01
  Total: $0.06

Time:
  60 × 0.1s = 6s
  25 × 0.3s = 7.5s
  10 × 2s = 20s
  5 × 2.5s = 12.5s
  Total: 46 seconds

Savings:
  Cost: 88% reduction ($0.50 → $0.06)
  Time: 77% reduction (200s → 46s)

الطبقة الوسطى (Florence-2) تعالج 85% الصور بتكلفة صفرةM SK3


وضع كل شيء معاً

هنا ' هو التدفق الكامل لGIF الميم مع الأشرطة

1. Load image: anchorman-not-even-mad.gif (93 frames)

2. IdentityWave (priority 10):
   → identity.frame_count = 93
   → identity.format = "gif"
   → identity.is_animated = true

3. TextLikelinessWave (priority 40, ~10ms):
   → Heuristic text detection: 15 regions in bottom 30%
   → Subtitle pattern: DETECTED
   → text.likeliness = 0.85

4. OcrWave (priority 50, ~60ms):
   → Run Tesseract OCR on first frame
   → ocr.text = "I'm not emn mad."  (garbled)
   → ocr.confidence = 0.62

5. MlOcrWave (priority 51, ~180ms):
   → Tesseract confidence < 0.95, run Florence-2
   → Sample 10 frames (animated GIF)
   → Run Florence-2 on each frame (parallel)
   → Deduplicate: 10 results → 2 unique texts
   → ocr.ml.multiframe_text = "I'm not even mad.\nThat's amazing."
   → ocr.ml.confidence = 0.91

6. OcrQualityWave (priority 58, ~5ms):
   → Check Florence-2 result
   → Spell check: 6/6 words correct (100%)
   → ocr.quality.is_garbled = false
   → ocr.quality.escalation_required = false

7. VisionLlmWave (priority 80, SKIPPED):
   → No escalation required (Florence-2 succeeded)

Final output:
  Text: "I'm not even mad.\nThat's amazing."
  Source: ocr.ml.multiframe_text
  Confidence: 0.91
  Cost: $0 (local processing)
  Time: ~250ms total (Tesseract + Florence-2)

إذا فشلت فلورانس-2 (الثقة < ♫0.5), ستستمر التدفقs

6. OcrQualityWave:
   → Spell check: 2/6 words correct (33%)
   → ocr.quality.is_garbled = true
   → ocr.quality.escalation_required = true

7. VisionLlmWave:
   → Create text-only filmstrip (2 regions, 450×49)
   → Send to Vision LLM: "Extract all text from this strip"
   → vision.llm.text = "I'm not even mad.\nThat's amazing."
   → Confidence: 0.95
   → Cost: ~$0.002 (30× token reduction vs full frames)
   → Time: ~2.3s

الإعداد

نظام الطبقة الثلاثة - قابلة للتركيب بالكامل :

{
  "DocSummarizer": {
    "Ocr": {
      "Tesseract": {
        "Enabled": true,
        "DataPath": "/usr/share/tesseract-ocr/4.00/tessdata",
        "Languages": ["eng"],
        "EarlyExitThreshold": 0.95
      },
      "Florence2": {
        "Enabled": true,
        "ModelPath": "models/florence2-base",
        "ConfidenceThreshold": 0.85,
        "MaxFrames": 10,
        "DeduplicationMethod": "levenshtein",
        "LevenshteinThreshold": 0.85
      },
      "Quality": {
        "SpellCheckThreshold": 0.5,
        "EscalationEnabled": true
      }
    },
    "VisionLlm": {
      "Enabled": true,
      "Provider": "ollama",
      "OllamaUrl": "http://localhost:11434",
      "Model": "minicpm-v:8b",
      "MaxRetries": 3,
      "TimeoutSeconds": 30
    },
    "Filmstrip": {
      "TextOnlyMode": true,
      "SubtitleRegionPercent": 0.3,
      "BrightPixelThreshold": 200,
      "TextChangeThreshold": 0.05
    },
    "Routing": {
      "FastRouteConfidence": 0.8,
      "BalancedRouteConfidence": 0.5,
      "TextDetectionEnabled": true
    }
  }
}

اشكال الفشل

الفشل الكشف الاستجابة
فشلت تيسيراكت الثقة < 0.7 أو إختبار الحروف < \0.5 الهروب إلى فلورانس -2
فلورانس-2 فشل الثقة < 0.5 أو إختبار الحروف < 0.5 الهروب إلى رؤية LLM
إنقطاع رؤية LLM الطلب يتجاوز 30s S العودة إلى أفضل نتيجة صوتية موجودة
فشلت جميع الطبقات جميع النتائج فارغة أو مشوهة أرجع السطر الفارغ بثقة
حد تكلفة API الميزانية اليومية تجاوزت لا يستطيعون الرؤية LLM, يستخدمون فلورانسM SK3 فقط
النموذج غير متوفر فلورانسM SK1Vision LLM offline Skip tier, continue to next

كل فشل هو محدد ومسجل مع provenance الكامل.


مقارنة مع المقاربات الأخرى

تقليدية: Tesseract + Manual Fallback

For each image:
  1. Run Tesseract
  2. If looks wrong, manually fix or skip

Problems:
- No middle tier (binary: works or doesn't)
- Manual intervention required
- No cost optimization

Cloud-First: دائماً تستخدم Vision LLM

For each image:
  1. Send to GPT-4o/Claude
  2. Pay $0.005-0.01 per image

Problems:
- Expensive (85% of images could be free)
- Slow (network latency)
- Still hallucinates without constraints

ثلاثة-Tier:LocalM SK2أول مع التزلج الذكي

For each image:
  1. OpenCV text detection (5-20ms, free)
  2. Route to appropriate tier
  3. Florence-2 handles 85% locally (200ms, free)
  4. Vision LLM only for complex cases (2-5s, $0.001-0.01)

Benefits:
- 88% cost reduction
- 77% faster (most images process locally)
- Deterministic escalation (auditable)
- Filmstrip optimization (30× token reduction)
- Constrained by deterministic signals

الاستنتاجات

لقد أثبتت أنابيب الأوCR الثلاثية الـ - أن Cost-aware routing و محلي- المعالجة الأولى يمكنه تحسين الأداء والاقتصاد بشكل كبير دون أن يهدئ الجودة.

الملاحظات الرئيسية:

  1. فلورانس-2 أونكس هو المكان المناسب: أفضل من Tesseract للخطوط المصممة, أسرع وأرخص من الـ Vision LLMs
  2. النص -لقطات فقط تحقق 30× تقليل الرموز: نستخرج الصناديق المزدوجة, ليست إطارات كاملة
  3. التوجيه هو محدد: إكتشاف CV المفتوح
  4. التسارع قابل للتحقق منه: كل مستوى يصدر إشارات من provenance
  5. إن الفشل مرحاً: سلسلة الأولوية تضمن العودة إلى أفضل مصدر متاح

مقياس النمط: تحليل محلي ديميائي → نموذج ML محلي → تتصاعد السحاب, كل الطبقة مع الخصائص المعروفة والتجارة بالتكاليف-offsM SK2

هذا هو الغموض المقيد الذي يطبق على الـ OCR : الإشارات التنقيبية ( اختبار اللاتغة \ , الكشف عن النص | ) نماذج تقليدية إفتراضية ♫ ( | فلورانس |-2, | الرؤية | LLM ٬ ), | والانتاج النهائي يجمع المصادر حسب الجودة ٬.


الموارد

مستندات LucidRAG

أدوات CLI

أبحاث

المقالات المرتبطة


السلسلة

جزء نمط تركيز
1 الغموض المقيد عنصر واحد
2 MoM مقيدة أجزاء متعددة
3 سحب السياق الوقت / الذاكرة
4 ذكاء الصورة فن العمارة الموجية, الأنماط
4.1 الأنبوب الثلاثي -Tier OCR (هذه المقالة) OCR, نماذج ONNX, شرائح الأفلام

التالي: الجزء 5 سيظهر كيف ImageSummarizer DocSummarizer, و المزيج للبيانات compose into multi-modal graph RAG with LucidRAG.

كل الأجزاء تتبع نفس المتغير: مكونات الإحتمالية تقترح ; أن الأنظمة الثابتة تستمر.

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.