VideoSummarizer: Reduced RAG for Video (Shots | → | Scenes |→ | Evidence (العربية (Arabic))

VideoSummarizer: Reduced RAG for Video (Shots | → | Scenes |→ | Evidence

Thursday, 15 January 2026

//

24 minute read

الوضع: في التطوير كجزء من lucidRAG. المصدر: github.comM SK1scottgal/lucidrag

أين يلائم هذا: VideoSummarizer هو الأوركسترا من lucidRAG العائلة, تدمج ثلاثة أنابيب في محرك تحليل فيديو موحد:

  • DocSummarizer - مستندات ( إستخراج الكائنات, رسمول المعرفةM SK3
  • ImageSummarizer - الصور (22- الذكاء البصري الموجي, مداخلات CLIPM SK3 OCRMSC4
  • AudioSummarizer - الصوت (الرسم الصوتيM SK2استهلاك السماعة, الترجمةMSC4
  • فيديو سوممارزر (هذه المقالة) - الفيديو ( ينظم كل الثلاثة, يضيف اللقطةMSC5 هيكل المشهدMSc6
  • المزيج للبيانات - البيانات ( إستنتاج الرسم التخطيطيM SK2 رسم الخرائط)

كلهم يتبعون نفس الشيء تخفيض نمط RAG: نستخرج الإشارات مرة واحدة , نحفظ الأدلة , ن синтезها مع مدخل LLM محدود


معالجة شريحة فيلم ساعتيّة بـ- بـ - بــ - بداخلات "CLIP" ستستغرق ساعات وتكلف مئات الدولارات في الحساب.

VideoSummarizer يحل هذا بثلاثة تحسينات رئيسية:

  1. تقليل الخش الحسي - تجاوز إطارات شبيهة بصريا قبل أن تكون مكلفة ML (40% تقليل
  2. دمج بطاقة CLIP - عملية 8 صور لكل مدخل GPU بدلا من واحد (3-5x تسارع
  3. تركيب أنابيب - صورة ChainSummarizer للحواسيب المفاتيح, صوتSum marizer للحديثM SK2 NER للوحدات

وكانت النتيجة : 2- ساعة من عملية الفيلم في ~10-15 دقائق , وليس ساعات S. نفس مبادئ العمارة كما ImageSummarizer و AudioSummarizer, لكن يتكون من أنابيب تحليل فيديو موحدة.

رؤية أساسية: الفيديو هو اللقطات + الصوت + النص. معالجة كل مجال باستخدام أدوات مخصصة

  • بنية العملية أولاً (cutsM SK1 I-frames , audio segments)
  • استخرج إشارات متقاطعة - مدوئية مرة واحدة (

المصطلحات:

  • إطلاق النار يأخذ الكاميرا بين التقاطات (بنية, من إكتشاف مشهد FFmpeg
  • مشهد مجموعة مترابطة من اللقطات التي تشكل وحدة متماسكة (semantic, من التجمع
  • الأدلة (start_time, end_time) + إشارات + اشارات + provenance

نماذج ML الرئيسية المستخدمة:

  • قفص OpenAI's Contrastive LanguageM SK1Image Pre-trainingMSC3 ينتج 512-dimensional embeddings that encode visual semantics
  • تصرخ نموذج التعرف على الكلام من OpenAI'; يقوم بترجمة الصوت إلى النص مع علامات زمنية
  • BERT-NER إدراك الكيان المسمى; يستخرج الناس, المنظماتM SK2 المواقع من النص
  • أونكس وقت التشغيل Cross-platform ML inference; runs models on CPUM SK2GPU without framework lockMSC3in

هذا المقال يغطي

  • كيف ينظم VideoSummarizer ثلاث خطوط أنابيب (ImageSommarizer, AudioSummarzer , NERM SK3
  • هيكلة الموجات: 16 موجات من الاستنساخ إلى توليد الأدلة
  • نظام القدرات: تحميل نماذج ضعيفةM SK1 كشف GPU, توجيه ردي فعل
  • تحسين حزمة "CLIP" لدمج الإطارات المفاتيح (3-5x أسرع)
  • تقليل الخش الإدراكي (40% تقليل الإطار )
  • متعددة -جمعات مشهدية للسائط (دمج | | + | transcript |+ | cut type |
  • إندماج NER لإستخراج الكيانات من المخطوطات
  • الذرات البدائية للحد من معدلات , تقدير زمني , والضغط الخلفي
  • ال sortie: المشهدات, اللقطات , TranscriptsM SK3 tracks text as RAG evidence

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


المشكلة: أن الفيديو مكلف

المؤشرات القياسية: الأرقام التي تم قياسها على AMD 9950X (16-core) МSK4 NVIDIA AM SK5 | | (16 | GB |) |

الفيلم العادي يحتوي على:

  • إطارات ~170,000 (2 ساعات عند 24fps)
  • ~2 ساعات من الصوت (الحديث, الموسيقىM SK2 المؤثرات )
  • طبقات نص متعددة (ترجمات,كتابة, على -كتابة شاشة)

المقاربة القشية ( لا أحد يفعل هذا , لكنه يحدد المقياس МSK2

  • إضافة CLIP لكل إطار: ~200ms × | | 170,000 | 9.4 ساعات
  • Vision LLM per frame: ~2s × | | 94 ساعات (cloud Vision API ballpark

حتى مع استخراج إطارات المفاتيح (sayM SK1 500-1000 frames), ذلكMSC4s لا يزال |100-200 ثوان من استنتاج السلسلة CLIP | .

النهج التقليدي: "إستخراج إطارات المفاتيح, أرسل إلى Vision LLM

المشكلة: هذا يحرق الحسابات على الإطارات المتفرطة (العديد من إطارات المفاتيح متشابهة بصريا), يعالجها بسلسلة ♫( معالجة GPU فارغة بين الإطارات ♫

الحل: متعددة- التصفية المراحلM SK2 معالجة العينات , وكون أسلاك الأنبوب


فن العمارة المدمجة في الفيديو

تطبيقات VideoSummarizer تقلل من RAG للفيديو بثلاثة مراحل

flowchart TB
    subgraph Input["Video File (.mp4, .mkv, etc.)"]
        V[Video Stream]
        A[Audio Stream]
    end

    subgraph Stage1["Stage 1: Structural Analysis"]
        N[NormalizeWave<br/>FFprobe metadata]
        SD[ShotDetectionWave<br/>Scene cuts via FFmpeg]
        KE[KeyframeExtractionWave<br/>I-frame + dedup]
    end

    subgraph Stage2["Stage 2: Content Extraction"]
        IS[ImageSummarizer<br/>CLIP, OCR, Vision]
        AS[AudioSummarizer<br/>Whisper, Diarization]
        NER[NER Service<br/>Entity extraction]
    end

    subgraph Stage3["Stage 3: Scene Assembly"]
        SC[SceneClusteringWave<br/>CLIP similarity]
        EV[EvidenceGenerationWave<br/>RAG chunks]
    end

    V --> N --> SD --> KE
    KE --> IS
    A --> AS
    AS --> NER
    IS --> SC
    NER --> SC
    SC --> EV

    style Stage1 stroke:#22c55e,stroke-width:2px
    style Stage2 stroke:#3b82f6,stroke-width:2px
    style Stage3 stroke:#8b5cf6,stroke-width:2px

أثار الأدلة التي تم إنتاجها

قبل أن تذهب إلى التنفيذ , هنا ' هذا ما تحصل عليهschema المخرجي

الأثر الحقول الرئيسية المصدر S
مشهد id, start_time, end_time, key_terms[], speaker_ids[], embedding[512] SceneClusteringWave
إطلاق النار id, start_time, end_time, cut_type, keyframe_path موجة إكتشاف الرصاص
التصريح id, text, start_time, end_time, speaker_id, confidence موجة الترجمة
نغمة نصية id, text, start_time, text_type (titleM SK1credit/subtitle /ocrMSC4 SubtitleExtractionWave
إطار مفاتيح id, timestamp, frame_path, dhash, clip_embedding[512] إطار مفاتيحExtractionWave

كل قطعة فنية تتضمن الموطن: موجة المصدرM SK1 علامة زمنية معالجة, درجة الثقةMSC3 هذا هو " مذكرة الدليلMNK5 التي تعمل على مستودعات RAG في الأسفل

إشارة - أنابيب الموجة الواعية

VideoSummarizer يستخدم بنية موجية مبنية على إشارة حيث كل موجه يعلن عن إتفاقاته الإشارات بشكل واضح:

public interface ISignalAwareVideoWave
{
    /// <summary>Signals this wave requires before it can run.</summary>

    IReadOnlyList<string> RequiredSignals { get; }

    /// <summary>Signals this wave can optionally use if available.</summary>

    IReadOnlyList<string> OptionalSignals { get; }

    /// <summary>Signals this wave emits on successful completion.</summary>

    IReadOnlyList<string> EmittedSignals { get; }

    /// <summary>Cache keys this wave produces for downstream waves.</summary>

    IReadOnlyList<string> CacheEmits { get; }

    /// <summary>Cache keys this wave consumes from upstream waves.</summary>

    IReadOnlyList<string> CacheUses { get; }
}

هذا يُمكن توازن الموجات الديناميكية:

  • تمر الأمواج تلقائياً إذا لم تكن هناك إشارات ضرورية
  • تحل الإعتمادات في وقت التشغيل (لا نظم مشفرة
  • إعادة التشغيل جزئية قابلة للتكرار (محفظة عن طريق مفاتيح الإشارة)
  • دقة تقدم UI: كل موجة ترسل التقدم بشكل مستقل

أنابيب موجة 16-

تم تنفيذ استخراج الإطارات الرئيسية كـ 7 موجات رقيقة لتحسين التوازن والكفاءة في الحواسيب.

الموجة الأولوية تتطلب الإنبثاق الوقت
NormalizeWave 1000 - video.duration, video.fps, video.normalized ~2s
موجة إكتشاف FFmpegShot 900 video.normalized shots.detected, shots.count ~5-10s
موجة إكتشاف IFrame 850 video.normalized keyframes.iframes_detected, keyframes.iframes_count ~3s
موجة إختيار إطار مفاتيح 840 shots.detected, keyframes.iframes_detected keyframes.selected, keyframes.selected_count ~1s
موجة استtraukة لقطة 830 keyframes.selected keyframes.thumbnails_extracted ~5s
موجة تفكيك إطار مفاتيح 820 keyframes.thumbnails_extracted keyframes.deduplicated, keyframes.duplicates_skipped ~1s
لوحة مفاتيح FullResExtractionWave 810 keyframes.deduplicated keyframes.extracted, keyframes.count ~10s
موجة الدمج الملتقط 800 keyframes.extracted clip.embeddings_ready, clip.embeddings_count ~30s
موجة تحليل الصورة 790 keyframes.deduplicated keyframes.analyzed, ocr.extracted ~60s
TitleCreditsDetectionWave 750 shots.detected title.detected, credits.detected ~5s
موجة الاستخراج الصوتي 650 video.normalized audio.extracted, audio.path ~30s
موجة الترجمة 600 audio.extracted transcription.complete, transcription.utterance_count ~120s
موجة استtractionsubtitle 550 video.normalized subtitles.extracted ~2s
فصل موجة الاستخراج 500 video.normalized chapters.extracted ~1s
موجة الـ SceneClustering 400 shots.detected scenes.detected, scene.count ~5s
موجة الأدلة 100 scenes.detected evidence.generated ~2s

ملاحظات:

  • تستخدم ImageAnalysisWave keyframes.deduplicated (لا كاملاً-resM SK2 يعمل التصوير بالرسوم المتحركة على شاشات اللقطة ; يستعمل تعليق الرؤية الكاملةMSC4res عندما يكون متاحاً عن طريق التوجيه للقدرة | .
  • الموجات 3-7 هي عبارة عن " إستخراج إطار مفاتيح | " | فرعي |- | أنابيب | МSK4 | موجات جزيئية للكفاءة في المخزن

الكلي لـ 2- ساعة من الفيلم: ~10-15 دقائق (vs. ساعات دون تحسين

حسنا- مفاتيح الإشارات المعروفة

الإشارات تُعرّف كثوابت للثبات:

public static class VideoSignals
{
    // NormalizeWave signals
    public const string VideoDuration = "video.duration";
    public const string VideoFps = "video.fps";
    public const string VideoNormalized = "video.normalized";

    // Shot detection signals
    public const string ShotsDetected = "shots.detected";
    public const string ShotsCount = "shots.count";

    // Keyframe signals
    public const string IframesDetected = "keyframes.iframes_detected";
    public const string KeyframesSelected = "keyframes.selected";
    public const string KeyframesDeduplicated = "keyframes.deduplicated";
    public const string KeyframesExtracted = "keyframes.extracted";

    // CLIP embedding signals
    public const string ClipEmbeddingsReady = "clip.embeddings_ready";

    // Scene clustering signals
    public const string ScenesDetected = "scenes.detected";
    public const string SceneCount = "scene.count";

    // Transcription signals
    public const string TranscriptionComplete = "transcription.complete";
}

نظام القدرات: نماذج بطيئة & السلسلة

VideoSummarizer يستخدم القدرة-بنية معمارية: إكتشاف GPU مرة واحدة عند البداية, تحميل النماذج ببطءM SK2 عمل طريق إلى المكونات المتاحةMSC3

مذكرة النموذج (YAML + النوعM SK2مستويات آمنة)

النماذج تم تعريفها في models.yamlلا توجد سلسلة سحرية في الرمز:

# models.yaml (excerpt)
models:
  clip-vit-b32:
    name: "CLIP ViT-B/32"
    download_url: "https://huggingface.co/openai/clip-vit-base-patch32/resolve/main/onnx/visual_model.onnx"
    preferred_providers: [CUDAExecutionProvider, DmlExecutionProvider, CPUExecutionProvider]

components:
  ClipEmbeddingWave:
    models: [clip-vit-b32]
    fallback_chain: [ImageAnalysisWave]
// Type-safe constants (no raw strings)
await coordinator.EnsureModelAsync(ModelIds.ClipVitB32);
await coordinator.ActivateWaveAsync(ComponentIds.TranscriptionWave);

// Route with fallback
var route = await coordinator.RouteWorkAsync(new[]
{
    ComponentIds.ClipEmbeddingWave,    // Primary (GPU)
    ComponentIds.ImageAnalysisWave     // Fallback (CPU)
});

أذرع كفاءة أنابيب

قيود السرعة , تخمين زمني , والضغط الخلفي التكيفي يحافظ على إستجابة الواجهة بينما يزيد من الإنتاجية

// Time estimation from actual data
var estimator = CapabilityAtoms.CreateTimeEstimator();
using (estimator.Time("clip_embedding")) { await ProcessAsync(); }
var eta = estimator.GetEstimate("clip_embedding", remaining: 50);
// eta.Estimated, eta.Optimistic, eta.Pessimistic, eta.Confidence

وثائق نظام القدرات الكاملة: أنظر Mostlylucid.Summarizer.Core/Capabilities/ للكشف عن GPU , ناقل إشارات / فرعي , , متحكمات الضغط الخلفي . , وتصميم بنية الشبكة


تحسين المفتاح 1: تقليل الخش الإدراكي

قبل تشغيل مداخلات CLIP باهظة الثمن, VideoSummarizer يفرز إطارات شبيهة بصريا باستخدام الاختلاف hash (dHash).

كيف يعمل dHash

public class KeyframeDeduplicationService
{
    // dHash parameters: 9x8 grayscale = 64 bits
    private const int HashWidth = 9;
    private const int HashHeight = 8;
    private const int DefaultHammingThreshold = 10;

    public async Task<ulong> ComputeDHashAsync(string imagePath, CancellationToken ct)
    {
        using var image = Image.Load<Rgba32>(imagePath);

        // Resize to 9x8 (one extra column for gradient comparison)
        image.Mutate(x => x
            .Resize(HashWidth, HashHeight)
            .Grayscale());

        ulong hash = 0;
        int bit = 0;

        // Compare adjacent pixels horizontally
        for (int y = 0; y < HashHeight; y++)
        {
            for (int x = 0; x < HashWidth - 1; x++)
            {
                var left = image[x, y].R;
                var right = image[x + 1, y].R;

                // Set bit if left pixel is brighter than right
                if (left > right)
                {
                    hash |= (1UL << bit);
                }
                bit++;
            }
        }

        return hash;
    }

    public static int HammingDistance(ulong a, ulong b) =>
        BitOperations.PopCount(a ^ b);
}

مخرج مثالي:

Input: 50 keyframe candidates (from codec I-frames)

Deduplication (Hamming threshold 10):
  Frame 0: hash=0x8f3a2c1d → KEEP (first frame)
  Frame 1: hash=0x8f3a2c1e → SKIP (distance=1 from frame 0)
  Frame 2: hash=0x8f3a2c1f → SKIP (distance=2 from frame 0)
  Frame 3: hash=0xc7e1b4a2 → KEEP (distance=28 from frame 0)
  ...

Result: 50 → 30 frames (40% reduction)
Processing saved: ~8 seconds of CLIP inference

لماذا يهم هذا؟

  • ~40% تقليل الإطار على المحتوى العادي
  • <1ms لكل إطار لحساب الهش (vsM SK1 200ms ل CLIP)
  • يصف الإطارات الإفراطية قبل عمليات GPU مكلفة

تحسين المفتاح 2: مداخلة بطاقة CLIP

بدلاً من معالجة صورة واحدة في وقت واحد

هندسة المعالجة الجماعية

public class BatchClipEmbeddingService
{
    private const int ClipImageSize = 224;
    private const int DefaultBatchSize = 8; // 8 images per GPU pass

    public async Task<Dictionary<int, float[]>> GenerateBatchEmbeddingsAsync(
        Dictionary<int, string> framePaths,
        int batchSize = DefaultBatchSize,
        CancellationToken ct = default)
    {
        var session = await GetOrLoadClipModelAsync(ct);
        var results = new Dictionary<int, float[]>();

        // Pre-index batch for O(1) lookup (not batch.IndexOf!)
        var batches = framePaths
            .Select((kvp, idx) => (idx, kvp.Key, kvp.Value))
            .Chunk(batchSize);

        foreach (var batch in batches)
        {
            // Create batch tensor [batchSize, 3, 224, 224]
            var tensor = new DenseTensor<float>(new[] { batch.Length, 3, ClipImageSize, ClipImageSize });

            // Preprocess images in parallel (simplified; production uses vectorised span copy)
            Parallel.ForEach(batch, item =>
            {
                var (batchIdx, frameIndex, path) = item;
                var localIdx = batchIdx % batchSize;
                PreprocessImageToTensor(path, tensor, localIdx); // ImageSharp pixel buffers
            });

            // Single GPU pass for entire batch
            var inputs = new List<NamedOnnxValue>
            {
                NamedOnnxValue.CreateFromTensor("input", tensor)
            };

            using var outputResults = session.Run(inputs);
            // Extract embeddings from batch output...
        }

        return results;
    }
}

مقارنة بالأداء:

Input: 30 keyframes (after deduplication)

Serial processing (1 frame at a time):
  30 × 200ms = 6,000ms (6.0 seconds)

Batch processing (8 frames per pass):
  4 batches × 350ms = 1,400ms (1.4 seconds)

Speedup: 4.3x

لماذا ينجح معالجة العينات:

  • متوازية GPU لا تستخدم بشكل جيد مع إفتراض صورة واحدة
  • طاقة الحزم [8, 3, 224, 224] يستخدم نفس ذاكرة GPU كالصورة الواحدة ( أغلب)
  • "ONNX Runtime" يحسن عمليات الحزم داخلياً

تحسين المفتاح 3: تركيب أنابيب

VideoSummarizer doesn't reinvent ImageSommarizer or AudioSum marizerit السلاسل هم.

لوحة مفاتيح فرعية -Pipeline: تجميع الصور

تم تقسيم إستخراج الإطارات الرئيسية إلى موجات 7 جزيئية ( أنظر إلى جدول الموجات في الأعلى | ). | هنا |' | هذا هو نمط التسلسل الذي يظهر كيف يربطون معاً

// IFrameDetectionWave → KeyframeSelectionWave → ThumbnailExtractionWave
// → KeyframeDeduplicationWave → KeyframeFullResExtractionWave → ClipEmbeddingWave

// ClipEmbeddingWave coordinates with ImageSummarizer
public class ClipEmbeddingWave : IVideoWave, ISignalAwareVideoWave
{
    public IReadOnlyList<string> RequiredSignals => [VideoSignals.KeyframesExtracted];
    public IReadOnlyList<string> EmittedSignals => [VideoSignals.ClipEmbeddingsReady];

    public async Task ProcessAsync(VideoContext context, CancellationToken ct)
    {
        var keyframes = context.GetCached<Dictionary<int, string>>("keyframes.paths");

        // Batch CLIP embedding (3-5x faster than serial)
        var embeddings = await _batchClipService.GenerateBatchEmbeddingsAsync(
            keyframes, batchSize: 8, ct);

        foreach (var (frameIndex, embedding) in embeddings)
            context.KeyframeEmbeddings[frameIndex] = embedding;
    }
}

// ImageAnalysisWave runs ImageSummarizer on deduplicated frames
public class ImageAnalysisWave : IVideoWave, ISignalAwareVideoWave
{
    public IReadOnlyList<string> RequiredSignals => [VideoSignals.KeyframesDeduplicated];

    public async Task ProcessAsync(VideoContext context, CancellationToken ct)
    {
        var keyframePaths = context.GetCached<List<string>>("keyframes.deduplicated_paths");

        foreach (var path in keyframePaths)
        {
            // Run ImageSummarizer for OCR, vision, captions
            var result = await _imageOrchestrator.AnalyzeAsync(path, ct);
            context.SetCached($"image_analysis.{Path.GetFileName(path)}", result);
        }
    }
}

TranscriptionWave: دمج AudioSummarizer

الاستخراج الصوتي والتحويل الصوتي هي الآن إشارات منفصلة

// AudioExtractionWave runs first (extracts audio track from video)
public class AudioExtractionWave : IVideoWave, ISignalAwareVideoWave
{
    public IReadOnlyList<string> RequiredSignals => [VideoSignals.VideoNormalized];
    public IReadOnlyList<string> EmittedSignals => ["audio.extracted", "audio.path"];

    public async Task ProcessAsync(VideoContext context, CancellationToken ct)
    {
        var audioPath = await _ffmpegService.ExtractAudioAsync(
            context.VideoPath, context.WorkingDirectory, ct);
        context.SetCached("audio.path", audioPath);
    }
}

// TranscriptionWave depends on audio.extracted signal
public class TranscriptionWave : IVideoWave, ISignalAwareVideoWave
{
    public IReadOnlyList<string> RequiredSignals => ["audio.extracted"];
    public IReadOnlyList<string> EmittedSignals => [
        VideoSignals.TranscriptionComplete,
        "transcription.utterance_count"
    ];

    public async Task ProcessAsync(VideoContext context, CancellationToken ct)
    {
        var audioPath = context.GetCached<string>("audio.path");

        // Run AudioSummarizer pipeline (Whisper + diarization)
        var audioProfile = await _audioOrchestrator.AnalyzeAsync(audioPath, ct);

        // Extract utterances with speaker info
        var turns = audioProfile.GetValue<List<SpeakerTurn>>("speaker.turns");
        foreach (var turn in turns ?? [])
        {
            context.Utterances.Add(new Utterance
            {
                Id = Guid.NewGuid(),
                Text = turn.Text,
                StartTime = turn.StartSeconds,
                EndTime = turn.EndSeconds,
                SpeakerId = turn.SpeakerId,
                Confidence = turn.Confidence
            });
        }

        // Run NER on full transcript for entity extraction
        var transcript = audioProfile.GetValue<string>("transcription.full_text");
        if (!string.IsNullOrEmpty(transcript))
        {
            var entities = await _nerService.ExtractEntitiesAsync(transcript, ct);
            context.SetCached("transcript_entities", entities);

            // Emit entity signals by type (PER, ORG, LOC, MISC)
            foreach (var group in entities.GroupBy(e => e.Type))
            {
                context.AddSignal($"transcript.entities.{group.Key.ToLowerInvariant()}",
                    group.Select(e => e.Text).Distinct().ToList());
            }
        }
    }
}

تكامل NER: التعرف على الكائنات المسمى

VideoSummarizer يستخرج كيانات مكتوبة باسمها من transcripts باستخدام BERT-based NER M SK1ONNX).

OnnxNerService

public class OnnxNerService
{
    // Model: dslim/bert-base-NER (ONNX exported)
    // Entities: PER (Person), ORG (Organization), LOC (Location), MISC (Miscellaneous)

    public async Task<List<EntitySpan>> ExtractEntitiesAsync(string text, CancellationToken ct)
    {
        var entities = new List<EntitySpan>();

        // Chunk long text (BERT max 512 tokens)
        foreach (var chunk in ChunkText(text, maxTokens: 400, overlap: 50))
        {
            // Tokenize with WordPiece
            var tokens = _tokenizer.Tokenize(chunk);

            // Run ONNX inference
            var inputs = PrepareInputs(tokens);
            using var results = _session.Run(inputs);

            // Decode BIO tags
            var predictions = DecodePredictions(results);
            var chunkEntities = ExtractEntitySpans(tokens, predictions);

            entities.AddRange(chunkEntities);
        }

        // Deduplicate entities
        return entities
            .GroupBy(e => (e.Text.ToLowerInvariant(), e.Type))
            .Select(g => g.First())
            .ToList();
    }
}

مخرج مثالي:

Transcript: "Today we're speaking with John Smith from Microsoft about
their new AI lab in Seattle. The project, codenamed Phoenix, builds
on research from Stanford University."

Entities extracted:
  PER: John Smith
  ORG: Microsoft, Stanford University
  LOC: Seattle
  MISC: Phoenix

Signals emitted:
  transcript.entities.per = ["John Smith"]
  transcript.entities.org = ["Microsoft", "Stanford University"]
  transcript.entities.loc = ["Seattle"]
  transcript.entities.misc = ["Phoenix"]

لماذا يهم NER في الفيديو:

  • فعّالة أسئلة مثل "بحث عن مقاطع فيديو تشير إلى مايكروسوفت"
  • Links to DocSummarizer entity graph
  • يقدم بيانات ملموسة بدون استنتاج LLM

العديد -كتشيف مشاهد إشارات

استخدام مداخلات CLIP وحدها للكشف عن المشهد لا ينجح ' القضبان الضئيلة من ناحية التصميم ( واحدة لكل لقطة تغيير | ), | لكن اللقطات كثيفة |. | مع | | مداخلة | لـ | لقطة | ومداخلات | 6 | تغطية | و | 7 | تجمع مداخلي نقي ينتج فقط | ما | 8 | مشهد | movie | ساعت |

VideoSummarizer يستخدم مقاربة إشارات متعددة - الذي يجمع إشارات 4 مع وزنها للكشف القوي عن الحدود في المشهد

SceneClusteringWave: Multi-ArchitectureSignal

public class SceneClusteringWave : IVideoWave, ISignalAwareVideoWave
{
    // Signal weights for boundary scoring
    private const double EmbeddingWeight = 0.4;   // CLIP embedding dissimilarity
    private const double TranscriptWeight = 0.3;  // Semantic shift in transcript
    private const double CutTypeWeight = 0.2;     // Fade/dissolve detection
    private const double TemporalWeight = 0.1;    // Time since last scene

    // Temporal constraints
    private const double MinSceneDuration = 15.0;   // Don't split scenes < 15s
    private const double MaxSceneDuration = 300.0;  // Force split at 5 minutes
    private const double TargetSceneDuration = 90.0; // Prefer ~90s scenes

    public IReadOnlyList<string> RequiredSignals => [VideoSignals.ShotsDetected];
    public IReadOnlyList<string> OptionalSignals => [
        VideoSignals.ClipEmbeddingsReady,
        VideoSignals.TranscriptionComplete,
        VideoSignals.KeyframesDeduplicated
    ];
    public IReadOnlyList<string> EmittedSignals => [
        VideoSignals.ScenesDetected,
        "scene.count",
        "scene.avg_duration",
        "scene.clustering_method"
    ];

    private List<(int shotIndex, double score)> ComputeBoundaryScores(VideoContext context)
    {
        var shots = context.Shots.OrderBy(s => s.StartTime).ToList();
        var scores = new List<(int, double)>();

        // Build embedding map with nearest-neighbor interpolation
        var shotEmbeddings = PropagateEmbeddingsToNearbyShots(context, shots);

        // Build transcript windows for semantic shift detection
        var transcriptWindows = BuildTranscriptWindows(context, shots, windowSeconds: 10);

        for (int i = 0; i < shots.Count - 1; i++)
        {
            double score = 0;
            var currentShot = shots[i];
            var nextShot = shots[i + 1];

            // 1. Embedding dissimilarity (40%)
            if (shotEmbeddings.TryGetValue(i, out var currentEmbed) &&
                shotEmbeddings.TryGetValue(i + 1, out var nextEmbed))
            {
                var similarity = CosineSimilarity(currentEmbed, nextEmbed);
                score += (1.0 - similarity) * EmbeddingWeight;
            }

            // 2. Transcript semantic shift (30%)
            if (transcriptWindows.TryGetValue(i, out var currentWords) &&
                transcriptWindows.TryGetValue(i + 1, out var nextWords))
            {
                var overlap = currentWords.Intersect(nextWords).Count();
                var union = currentWords.Union(nextWords).Count();
                var jaccard = union > 0 ? (double)overlap / union : 0;
                score += (1.0 - jaccard) * TranscriptWeight;
            }

            // 3. Cut type signal (20%) - fades/dissolves suggest scene boundaries
            if (currentShot.CutType is "fade" or "dissolve")
            {
                score += CutTypeWeight;
            }

            // 4. Temporal pressure (10%) - encourage splits near target duration
            var timeSinceLastScene = currentShot.EndTime - GetLastSceneBoundary();
            if (timeSinceLastScene > TargetSceneDuration)
            {
                var pressure = Math.Min(1.0, (timeSinceLastScene - TargetSceneDuration) / 60);
                score += pressure * TemporalWeight;
            }

            scores.Add((i, score));
        }

        return scores;
    }
}

الابتكارات الرئيسية

  1. أقرب -نشر مركبة جيران: فقط ~2% من اللقطات لديها مداخلات CLIP مباشرة. المقاربة الجديدة تنشر المداخلات لطلقات قريبة خلال 30 ثواني باستخدام وزن القرب الزمنيM SK4

  2. النوافذ الدلالية للترجمة: يبني 10- نافذة كلمة ثانية حول كل لقطة ويكشف التنقلات الدلالية من خلال المسافة عبر جاككارد بروكسة الهبوط الدلالي الرخيص | ( | تقليل النسخ |= | تغيير الموضوع | МSK4 | BM | 25 | يمكن استخدام النسخ أو الهبوط المدمج عندما يكون موجودا |

  3. إدراك نوع القطع: الخفاء-toM SK2 التحولات السوداء والانحلال تشير بقوة إلى الحدود في المشهد , ترفع النتيجة الحدودية .

  4. الحد المتكيف: عوضاً عن حد محدد, يختار الحدود من الأعلى 25% من الدرجات

  5. القيود المؤقتة: يفرض الحد الأدنى 15 مشاهدته ويقوض حدوده في 5- अधिकतम دقيقة .

مثال:

Input: 1881 shots from a 2-hour movie
       39 keyframes with CLIP embeddings
       2302 utterances from transcript

Boundary scoring per shot:
  Shot 45-46: embedding=0.15, transcript=0.32, cut=0.0, temporal=0.0 → score=0.156
  Shot 46-47: embedding=0.08, transcript=0.12, cut=0.0, temporal=0.0 → score=0.068
  Shot 47-48: embedding=0.35, transcript=0.41, cut=0.2, temporal=0.05 → score=0.388 ← BOUNDARY
  ...

Adaptive threshold (top 25%): 0.25
Natural boundaries found: 45

Output: 47 scenes (avg 2.6 minutes per scene)
  - Min scene: 15.2s
  - Max scene: 298.4s
  - Total coverage: 100%

Signals:
  scenes.detected = true
  scene.count = 47
  scene.avg_duration = 156.3
  scene.clustering_method = "multi_signal_weighted"

عقد إشارات الفيديو

VideoSummarizer يمد إتصال الإشارات من ImageSumMarizer و AudioSum marizer:

public record VideoSignal
{
    public required string Key { get; init; }      // "scene.count", "transcript.entities.per"
    public object? Value { get; init; }
    public double Confidence { get; init; } = 1.0;
    public required string Source { get; init; }   // "SceneClusteringWave"

    // Video-specific: time range
    public double? StartTime { get; init; }
    public double? EndTime { get; init; }

    public DateTime Timestamp { get; init; }
    public Dictionary<string, object>? Metadata { get; init; }
    public List<string>? Tags { get; init; }       // ["visual", "scene"]
}

public static class VideoSignalTags
{
    public const string Visual = "visual";
    public const string Audio = "audio";
    public const string Speech = "speech";
    public const string Ocr = "ocr";
    public const string Motion = "motion";
    public const string Scene = "scene";
    public const string Shot = "shot";
    public const string Metadata = "metadata";
}

الإشارات الرئيسية المنبعثة

إشارة المصدر
video.duration أعادة موجة مدة كاملة في ثواني
video.resolution إحداث موجة طبيعية عرض× طول
video.fps موجة عادية معدل الإطار
shots.count موجة إكتشاف الرصاص عدد الرصاصات التي تم إكتظافها
keyframes.count لوحة مفاتيح موجة استخلاص لوحات مفاتح فريدة بعد التراجع
keyframes.duplicates_skipped KeyframeExtractionWave Frames filtered by dHash
scene.count موجة الـ SceneClustering
transcript.entities.per موجة الترجمة أسماء الأشخاص من النطاق الشمالي للطاقة النووية
transcript.entities.org موجة الترجمة أسماء المنظمات
transcript.word_count موجة التحويل كل الكلمات في التحويل

VideoPipeline: выход RAG

الـ VideoPipeline يحول إشارات الفيديو إلى ContentChunk لمؤشر RAG:

public class VideoPipeline : PipelineBase
{
    public override string PipelineId => "video";
    public override IReadOnlySet<string> SupportedExtensions => new HashSet<string>
    {
        ".mp4", ".mkv", ".avi", ".mov", ".wmv", ".webm", ".flv", ".m4v", ".mpeg", ".mpg"
    };

    private List<ContentChunk> BuildContentChunks(VideoContext context, string filePath)
    {
        var chunks = new List<ContentChunk>();

        // 1. Scene-based chunks (best for video retrieval)
        foreach (var scene in context.Scenes)
        {
            var sceneText = BuildSceneText(context, scene);
            var embedding = context.GetCached<float[]>($"scene_centroid.{scene.Id}");

            chunks.Add(new ContentChunk
            {
                Text = sceneText,
                ContentType = ContentType.Summary,
                Embedding = embedding,  // Proper vector column, not metadata
                Metadata = new Dictionary<string, object?>
                {
                    ["source"] = "video_scene",
                    ["scene_id"] = scene.Id,
                    ["key_terms"] = scene.KeyTerms,
                    ["speakers"] = scene.SpeakerIds,
                    ["start_time"] = scene.StartTime,
                    ["end_time"] = scene.EndTime
                }
            });
        }

        // 2. Transcript chunks (1-minute windows)
        var transcriptChunks = BuildTranscriptChunks(context, filePath);
        chunks.AddRange(transcriptChunks);

        // 3. Text track chunks (on-screen text/subtitles)
        foreach (var textTrack in context.TextTracks)
        {
            chunks.Add(new ContentChunk
            {
                Text = $"On-screen text: {textTrack.Text}",
                ContentType = ContentType.ImageOcr,
                Metadata = new Dictionary<string, object?>
                {
                    ["source"] = "video_ocr",
                    ["text_type"] = textTrack.TextType.ToString(),
                    ["start_time"] = textTrack.StartTime
                }
            });
        }

        return chunks;
    }

    private string BuildSceneText(VideoContext context, SceneSegment scene)
    {
        var parts = new List<string>();

        if (!string.IsNullOrEmpty(scene.Label))
            parts.Add($"Scene: {scene.Label}");

        parts.Add($"[{FormatTime(scene.StartTime)} - {FormatTime(scene.EndTime)}]");

        if (scene.KeyTerms.Count > 0)
            parts.Add($"Topics: {string.Join(", ", scene.KeyTerms)}");

        // Add utterances in this scene
        var sceneUtterances = context.Utterances
            .Where(u => u.StartTime >= scene.StartTime && u.EndTime <= scene.EndTime)
            .OrderBy(u => u.StartTime);

        if (sceneUtterances.Any())
            parts.Add($"Speech: {string.Join(" ", sceneUtterances.Select(u => u.Text))}");

        return string.Join("\n", parts);
    }
}

مخرج مثالي للفيلم:

{
  "chunks": [
    {
      "text": "Scene: Opening montage\n[0:00 - 2:34]\nTopics: city, night, traffic\nSpeech: The year is 2049. The world has changed.",
      "contentType": "Summary",
      "metadata": {
        "source": "video_scene",
        "scene_id": "abc123",
        "key_terms": ["city", "night", "traffic"],
        "start_time": 0.0,
        "end_time": 154.0
      }
    },
    {
      "text": "The detective arrived at the crime scene. Forensics had already processed the area.",
      "contentType": "Transcript",
      "metadata": {
        "source": "video_transcript",
        "time_window": "2:34 - 3:34",
        "utterance_count": 4
      }
    },
    {
      "text": "On-screen text: LOS ANGELES 2049",
      "contentType": "ImageOcr",
      "metadata": {
        "source": "video_ocr",
        "text_type": "Title"
      }
    }
  ]
}

خصائص الأداء

زمن المعالجة (2-صورة ساعةM SK1 1080p)

المرحلة الوقت ملاحظات
بيانات ملموسة FF ~2s
إكتشاف الرصاص MSC2s MSC3 فلتر مشهد FFmpeg S
إستخراج إطارات مفاتيح ~30s 500 I - frames
تفكيك دوتة "dHash" MSC2s MSC3 \MSC4 MSC5 MSC6 إطارات msc7
مدمجة بطاقة CLIP
ImageSummarizer OCR
إستخراج الصوت MSC2s MSC3 FFmpeg msc4
ترجمة صامتة ~180s 2 ساعات الكلام
التلوث الصوتي ~60s S ECAPA-TDNN
استخراج النيترونات ~10s BERT - النيرونات على الطباعة
تجميع المشهد ~5s S |
مولد الأدلة ~2s SSK3
كل ~8-10 دقائق

بدون تحسينات

تحسين توفير
تفكيك دوتنه dHash ~40% إطارات تلقح МSK3 ♫~24s حفظ الاقتران ♫
توصيل بطاقة 3-5x أسرع = ~180 حفظت
تركيب أنابيب استخدام ImageSummarizer
الادخار الكلي ~3-4 دقائق

استخدام الذاكرة

مكون الذاكرة
CLIP ViT
قاعدة الشم MSC2MB MSC3
ECAPA-TDNN
BERT-NER ~500MB
القمة ~1.5GB

التكامل مع lucidRAG

يسجل الفيديو سوممارزر كـ IPipeline للتوجيهات الآلية:

// In Program.cs
builder.Services.AddDocSummarizer(builder.Configuration.GetSection("DocSummarizer"));
builder.Services.AddDocSummarizerImages(builder.Configuration.GetSection("Images"));
builder.Services.AddVideoSummarizer();  // NEW
builder.Services.AddPipelineRegistry(); // Must be last

// Auto-routing by extension
var registry = services.GetRequiredService<IPipelineRegistry>();
var pipeline = registry.FindForFile("movie.mp4");  // Returns VideoPipeline
var result = await pipeline.ProcessAsync("movie.mp4");

التوسعات المدعمة:

  • .mp4, .mkv, .avi, .mov, .wmv, .webm, .flv, .m4v, .mpeg, .mpg

ما تحصل عليه

  • Scene-جزء RAG المستوى: Segments coherents with transcripts, key termsM SK2 speaker IDs
  • أدلة مُعدية: مرئية ( مداخلات الإطار السفلي ), صوتية | | ( | تحوي المتكلمين |), | نص |
  • الوحدات المسمولة: الناسM SK1 المنظمات, المواقع من transcript NER
  • provenance قابل للaudit: كل إشارة لديها موجة المصدر , ثقة
  • المعالجة الفعالة: 10-15 دقائق لـ 2- فيلم ساعة ( لا ساعات

ما تكلفه

  • ~1.5GB حافظة GPU لكل نماذج ONNX
  • ~8-10 معالجة الدقيقة لكل 2- ساعة من الفيلم
  • فضاء الحاسوب للدوتنې الوسطى (تم تنظيفها تلقائياً)
  • التعقيد: تنظيم ثلاثة أنابيب يتطلب فهم إعتماد الأمواج

الاستنتاجات

ويعرض الفيديو سوممارزر أن تركيب خطوط الأنابيب الدرجات

  1. إعادة استخدام خطوط الأنابيب المتخصصة: Don't reinvent ImageSummarizer or AudioSommarizerchain them
  2. فلتر قبل عمليات مكلفة: تكاليف تقليل هش <1ms, توفر 40% من استنتاج CLIP
  3. عمليات بطاقة GPU: 8 صور لكل تمرير
  4. استخرج الهيكل قبل المحتوى: اللقطات → المشاهد → الأدلة ( ليست إطارات خامة | → | LLM | )
  5. إدارة النماذج البطيئة: تحميل النماذج فقط عند الحاجة, الكشف عن GPU تلقائيا
  6. التوجيه التفاعلي: عمل الطريق إلى المكونات المتاحة, التراجع بجمال

والنتيجة : فيلم ساعتي 2- يتحول إلى مسجل إشارات بنائي مع مشاهد ,, , Transcripts , , , Entities ., , and embeddingsready for RAG queries like .

  • "أبحث عن المشاهد التي يناقش فيها جون سميث مايكروسوفت
  • "أظهر مقاطع الفيديو مع النص على الشاشة - عن مشروع فينكس
  • "ابحث عن مقاطع فيديو متشابهة مع هذه المشهد" (CLIP تداخل البحثM SK3

نمط RAG المنخفض لفيديو:

Ingestion:  Video → 16 waves → Signals + Evidence (scenes, transcripts, entities)
Storage:    Signals (indexed) + Embeddings (CLIP, voice) + Evidence (chunks)
Query:      Filter (SQL) → Search (BM25 + vector) → Synthesize (LLM, ~5 results)

نظام القدرات:

Startup:    Detect GPU → Load ModelManifest (YAML) → Initialize SignalSink
Activation: Component requests model → Lazy download → Signal "ModelAvailable"
Routing:    Route to best provider → Fallback chain → Backpressure control
Atoms:      Rate limiting + Time estimation + Pipeline balancing

هذا هو الغموض المقيد على المقياس:

  • مكونات الإحتمالية تقترح إشارات: مداخلات (CLIP), فرضيات الرسم البياني
  • التقييم الإفتراضي يجمع الهيكل: نقاط الحدود المُزنة, اختيار الحد الفاصلM SK2 القيود الزمنية
  • LLM (optional) ينتج من الأدلة: السياق المحدود, provenance قابل للتحقق

الـ LLM يعمل على ما قبل - "الدلائل الحاسوبية" وليس الفيديو الخام"


الموارد

الوثائق لـ lucidRAG

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

نماذج أونكس

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

الأنماط الأساسية:

تطبيقات RAG المنخفضة


السلسلة

جزء نمط تركيز
1 الغموض المقيد عنصر واحد
2 MoM مقيدة أجزاء متعددة
3 سحب السياق الوقت / الذاكرة
4 ذكاء الصورة فن العمارة الموجية, 22 موجات
4.1 خط ثلاثي -Tier OCR OCRM SK1 نماذج ONNX, شرائح الأفلام
4.2 AudioSummarizer الصوت القضائي, تشلل السماعة
4.3 VideoSummarizer (this article) الأوركستريشن التلفزيوني, بستة CLIP, NER

التالي: متعددة-رسم بياني مدوئي RAG مع lucidRAG يجمع كل الأربعة ملخصات إلى رسم بياني علمي موحد مع متقاطعةM SK2ربط الكيان المدوئي .

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

Finding related posts...
logo

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