Back to "AI-Powered Alt Text Generation met veelal lucid.llmlltText"

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

Accessibility AI ASP.NET Florence-2 Image Processing NuGet

AI-Powered Alt Text Generation met veelal lucid.llmlltText

Monday, 24 November 2025

Wilt u mooie, beschrijvende alt tekst voor afbeeldingen op uw sites of jsut extraheren tekst van hen? mostlylucid.llmalttext maakt gebruik van Microsoft's Florence-2 visie taal model om hoge kwaliteit alt tekst automatisch te genereren - volledig lokaal draait op uw machine, geen API sleutels nodig.

Opmerking: Ik moet deze doc updaten nu de nuget-pakket Als je kijkt... Hier. je zult fijn een handige demo site die u kunt downloaden en gebruiken. Ik zal dit bijwerken met details in de komende dagen.

NuGet Licentie: Unlicense

Inleiding

Alt tekst is belangrijk. Screen lezers hangen ervan af, SEO rankings factor het in, en het is gewoon het juiste ding om te doen voor toegankelijkheid. Maar het schrijven van goede alt tekst voor honderden afbeeldingen? Dat is waar de meesten van ons tekort komen.

Dit pakket lost dat probleem op met behulp van Microsoft's Florence-2 visie taalmodel - volledig lokaal draait op uw machine, geen API sleutels nodig.

Broncode: github.com/scottgal/meestallucid.nugetpackages

Het probleem

Elke <img> tag zou betekenisvolle alt tekst moeten hebben. Maar in de praktijk:

  • Handmatig schrijven is vervelend. - honderden beelden betekent uren werk
  • AI API's kosten geld - OpenAI Vision, Claude, etc. snel optellen
  • Privacyproblemen - u wilt geen afbeeldingen naar externe API's sturen
  • Inconsistente kwaliteit - verschillende mensen schrijven alt tekst anders

Wat als je alt-tekst van hoge kwaliteit automatisch kunt genereren, volledig draait op je eigen hardware?

Hoe het werkt

Het pakket maakt gebruik van Microsoft's Florence-2 model via ONNX runtime. Hier is de verwerkingspijplijn:

flowchart TB
    subgraph Input[Image Sources]
        A[File Path]
        B[URL]
        C[Stream]
        D[Byte Array]
    end

    subgraph Processing[Florence-2 Pipeline]
        E[Image Preprocessing]
        F[Vision Encoder]
        G[Language Decoder]
    end

    subgraph Output[Results]
        H[Alt Text]
        I[OCR Text]
        J[Content Type]
    end

    A --> E
    B --> E
    C --> E
    D --> E
    E --> F
    F --> G
    G --> H
    G --> I
    G --> J

    style A stroke:#10b981,stroke-width:2px
    style B stroke:#10b981,stroke-width:2px
    style C stroke:#10b981,stroke-width:2px
    style D stroke:#10b981,stroke-width:2px
    style F stroke:#6366f1,stroke-width:2px
    style G stroke:#6366f1,stroke-width:2px
    style H stroke:#ec4899,stroke-width:2px
    style I stroke:#ec4899,stroke-width:2px
    style J stroke:#ec4899,stroke-width:2px

Belangrijkste kenmerken:

  • Lokale uitvoering - geen API-gesprekken, geen kosten, geen privacyproblemen
  • ~800MB model - één keer downloaden, voor altijd gecached
  • Meerdere takentypes - korte bijschriften, gedetailleerde beschrijvingen, OCR
  • Inhoudsclassificatie - weet of het een foto, grafiek, screenshot, enz. is.

Snel starten

Installatie

dotnet add package Mostlylucid.LlmAltText

Diensten registreren

// Program.cs
builder.Services.AddAltTextGeneration();

De eerste run downloadt het Florence-2 model (~800MB), dan ben je klaar om te gaan.

Alttekst aanmaken

public class ImageController : ControllerBase
{
    private readonly IImageAnalysisService _imageAnalysis;

    public ImageController(IImageAnalysisService imageAnalysis)
    {
        _imageAnalysis = imageAnalysis;
    }

    [HttpPost("analyze")]
    public async Task<IActionResult> Analyze(IFormFile image)
    {
        using var stream = image.OpenReadStream();
        var altText = await _imageAnalysis.GenerateAltTextAsync(stream);

        return Ok(new { altText });
    }
}

Meerdere invoerbronnen

De dienst accepteert afbeeldingen van overal - bestanden, URL's, streams, of byte arrays.

Van bestandspad

var altText = await _imageAnalysis.GenerateAltTextFromFileAsync("/images/photo.jpg");

Van URL

var altText = await _imageAnalysis.GenerateAltTextFromUrlAsync(
    "https://example.com/image.png");

Van stroom

using var stream = file.OpenReadStream();
var altText = await _imageAnalysis.GenerateAltTextAsync(stream);

Van Byte Array

var bytes = await httpClient.GetByteArrayAsync(imageUrl);
var altText = await _imageAnalysis.GenerateAltTextAsync(bytes);

Taaktypes: Detailniveau controleren

Florence-2 ondersteunt drie bijschriften. Kies op basis van uw behoeften:

// Brief - "A dog sitting on grass"
var brief = await _imageAnalysis.GenerateAltTextAsync(stream, "CAPTION");

// Detailed - "A golden retriever sitting on green grass in a park"
stream.Position = 0;
var detailed = await _imageAnalysis.GenerateAltTextAsync(stream, "DETAILED_CAPTION");

// Most detailed (default) - Full accessibility description
stream.Position = 0;
var full = await _imageAnalysis.GenerateAltTextAsync(stream, "MORE_DETAILED_CAPTION");
// "A happy golden retriever with light fur sitting on lush green grass
//  in a sunny park, with trees visible in the background."

Wanneer te gebruiken:

Taaktype Best Voor |-----------|----------| | CAPTION Miniaturen, decoratieve afbeeldingen, snelle tooltips | DETAILED_CAPTION Sociale media, basistoegankelijkheid | MORE_DETAILED_CAPTION Volledige toegankelijkheid, schermlezers (aanbevolen)

OCR-tekstextractie

Florence-2 kan ook tekst uit afbeeldingen halen - nuttig voor screenshots, documenten en grafieken.

// Extract text only
var extractedText = await _imageAnalysis.ExtractTextAsync(stream);

// Get both alt text and extracted text
var (altText, ocrText) = await _imageAnalysis.AnalyzeImageAsync(stream);

Console.WriteLine($"Alt: {altText}");
Console.WriteLine($"OCR: {ocrText}");

Inhoudstype-classificatie

Niet alle afbeeldingen zijn hetzelfde. Een foto heeft een beschrijvende alt tekst nodig; een document heeft de tekstinhoud nodig. De classificatiefunctie helpt u elk goed te behandelen:

var result = await _imageAnalysis.AnalyzeWithClassificationAsync(stream);

Console.WriteLine($"Type: {result.ContentType}");        // e.g., "Photograph"
Console.WriteLine($"Confidence: {result.ContentTypeConfidence:P0}"); // e.g., "87%"
Console.WriteLine($"Has Text: {result.HasSignificantText}");

Omgaan met verschillende inhoudstypen

var result = await _imageAnalysis.AnalyzeWithClassificationAsync(stream);

switch (result.ContentType)
{
    case ImageContentType.Document:
        // Documents - prioritize extracted text
        return result.ExtractedText;

    case ImageContentType.Screenshot:
        // Screenshots - combine description with UI text
        return result.HasSignificantText
            ? $"{result.AltText}. Text visible: {result.ExtractedText}"
            : result.AltText;

    case ImageContentType.Chart:
        // Charts - describe the visualization plus data
        return $"{result.AltText}. Data: {result.ExtractedText}";

    case ImageContentType.Photograph:
    default:
        // Photos - just the description
        return result.AltText;
}

Referentie van het type inhoud

Beschrijving van het type: Voorbeeld: |------|-------------|---------| | Photograph Real-world foto's Mensen, landschappen, producten | Document Text-heavy content PDF's, formulieren, artikelen | Screenshot De software vangt de UI, websites, apps | Chart Data visualisaties Graphs, taart grafieken, tabellen | Illustration Kunstwerk, tekenfilms, pictogrammen | Diagram Technische tekeningen Flowcharts, UML, schema's | Unknown Niet-ingedeelde Edge cases

De Auto Alt Tekst TagHelper

Hier is waar het interessant wordt. De TagHelper genereert automatisch alt tekst voor elke <img> tag ontbreekt een - op render tijd.

Instellen

// Program.cs
builder.Services.AddAltTextGeneration(options =>
{
    options.EnableTagHelper = true;
    options.EnableDatabase = true;  // Cache results
    options.DbProvider = AltTextDbProvider.Sqlite;
    options.SqliteDbPath = "./alttext.db";
});

var app = builder.Build();
await app.Services.MigrateAltTextDatabaseAsync();

Registreer de TagHelper in _ViewImports.cshtml:

@addTagHelper *, Mostlylucid.LlmAltText

Hoe het werkt

flowchart LR
    subgraph Razor[Razor View Rendering]
        A[img tag found]
        B{Has alt attribute?}
        C[Skip - use existing]
        D{In cache?}
        E[Return cached]
        F[Fetch image]
        G[Generate alt text]
        H[Cache result]
        I[Render with alt]
    end

    A --> B
    B -->|Yes| C
    B -->|No| D
    D -->|Yes| E
    D -->|No| F
    F --> G
    G --> H
    H --> I
    E --> I

    style A stroke:#10b981,stroke-width:2px
    style B stroke:#6366f1,stroke-width:2px
    style G stroke:#ec4899,stroke-width:2px
    style I stroke:#8b5cf6,stroke-width:2px

Wat verwerkt wordt

<!-- NO ALT - Will be processed -->
<img src="https://example.com/photo.jpg" />

<!-- HAS ALT - Skipped (respects your text) -->
<img src="https://example.com/photo.jpg" alt="My custom description" />

<!-- EMPTY ALT - Skipped (decorative image per a11y standards) -->
<img src="https://example.com/decorative.jpg" alt="" />

<!-- EXPLICIT SKIP - Skipped -->
<img src="https://example.com/photo.jpg" data-skip-alt="true" />

<!-- DATA URI - Skipped (can't fetch) -->
<img src="data:image/png;base64,..." />

<!-- RELATIVE PATH - Skipped (needs absolute URL) -->
<img src="/images/photo.jpg" />

Domeinbeperkingen

Voor de beveiliging, kunt u beperken welke domeinen de TagHelper zal halen uit:

options.AllowedImageDomains = new List<string>
{
    "mycdn.example.com",
    "images.mysite.org",
    "cdn.githubusercontent.com"
};

Database caching

Zonder caching zou elke pagina render alt tekst regenereren. Dat is traag en verspillend. De database cache slaat resultaten op die door image URL worden getoetst.

SQLite (Ontwikkeling)

builder.Services.AddAltTextGeneration(options =>
{
    options.EnableDatabase = true;
    options.DbProvider = AltTextDbProvider.Sqlite;
    options.SqliteDbPath = "./alttext.db";
    options.CacheDurationMinutes = 60;
});

PostgreSQL (productie)

builder.Services.AddAltTextGeneration(options =>
{
    options.EnableDatabase = true;
    options.DbProvider = AltTextDbProvider.PostgreSql;
    options.ConnectionString = Configuration.GetConnectionString("AltTextDb");
});

Configuratiereferentie

builder.Services.AddAltTextGeneration(options =>
{
    // Model location (~800MB downloaded here)
    options.ModelPath = "./models";

    // Default task type for alt text generation
    options.DefaultTaskType = "MORE_DETAILED_CAPTION";

    // Maximum word count for alt text
    options.MaxWords = 90;

    // Enable detailed logging
    options.EnableDiagnosticLogging = true;

    // TagHelper settings
    options.EnableTagHelper = true;
    options.EnableDatabase = true;
    options.AutoMigrateDatabase = true;

    // Database provider
    options.DbProvider = AltTextDbProvider.Sqlite;
    options.SqliteDbPath = "alttext.db";
    // or
    options.DbProvider = AltTextDbProvider.PostgreSql;
    options.ConnectionString = "Host=localhost;Database=alttext;...";

    // Security
    options.AllowedImageDomains = new List<string> { "cdn.example.com" };
    options.SkipSrcPrefixes = new List<string> { "data:", "blob:" };

    // Caching
    options.CacheDurationMinutes = 60;
});

Real-World Voorbeeld: Batch Processing

Hier is hoe ik het gebruik om afbeeldingen te verwerken bij het importeren van blogberichten:

public class ImageProcessor
{
    private readonly IImageAnalysisService _imageAnalysis;
    private readonly ILogger<ImageProcessor> _logger;

    public ImageProcessor(
        IImageAnalysisService imageAnalysis,
        ILogger<ImageProcessor> logger)
    {
        _imageAnalysis = imageAnalysis;
        _logger = logger;
    }

    public async Task ProcessMarkdownImagesAsync(string markdownPath)
    {
        var imageDir = Path.Combine(Path.GetDirectoryName(markdownPath)!, "images");
        if (!Directory.Exists(imageDir)) return;

        var images = Directory.GetFiles(imageDir, "*.*")
            .Where(f => IsImageFile(f));

        foreach (var imagePath in images)
        {
            try
            {
                var result = await _imageAnalysis
                    .AnalyzeWithClassificationFromFileAsync(imagePath);

                _logger.LogInformation(
                    "Processed {File}: {Type} ({Confidence:P0})",
                    Path.GetFileName(imagePath),
                    result.ContentType,
                    result.ContentTypeConfidence);

                // Store alt text for later use
                await SaveAltTextAsync(imagePath, result.AltText);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to process {File}", imagePath);
            }
        }
    }

    private static bool IsImageFile(string path)
    {
        var ext = Path.GetExtension(path).ToLowerInvariant();
        return ext is ".jpg" or ".jpeg" or ".png" or ".gif" or ".webp" or ".bmp";
    }
}

Prestatieoverwegingen

Wat te verwachten

Typische waarde |--------|--------------| Laag (~800MB model downloaden) Laag (~800MB model downloaden) Modelbelasting in seconden Per beeldverwerking 500-2000ms Geheugengebruik 2GB+ aanbevolen Schijfruimte 800MB voor modellen

Tips voor de productie

// 1. Register as Singleton (model load is expensive)
builder.Services.AddAltTextGeneration(); // Already singleton internally

// 2. Check readiness before processing
if (!_imageAnalysis.IsReady)
{
    return StatusCode(503, "AI model still initializing");
}

// 3. Use cancellation tokens for timeouts
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var altText = await _imageAnalysis.GenerateAltTextFromUrlAsync(url, cts.Token);

// 4. Process in batches, not parallel (memory constraints)
foreach (var image in images)
{
    await ProcessImageAsync(image); // Sequential is safer
}

OpenTelemetrie-integratie

Het pakket omvat ingebouwde opsporing:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing.AddSource("Mostlylucid.LlmAltText");
    });

Getraceerde activiteiten:

  • llmalttext.generate_alt_text
  • llmalttext.extract_text
  • llmalttext.analyze_image
  • llmalttext.classify_content_type

Gezondheidscontroles

Voeg een gezondheidscontrole toe om de status van het model te controleren:

public class AltTextHealthCheck : IHealthCheck
{
    private readonly IImageAnalysisService _service;

    public AltTextHealthCheck(IImageAnalysisService service)
        => _service = service;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default)
    {
        return Task.FromResult(_service.IsReady
            ? HealthCheckResult.Healthy("Florence-2 model ready")
            : HealthCheckResult.Unhealthy("Model not initialized"));
    }
}

// Registration
builder.Services.AddHealthChecks()
    .AddCheck<AltTextHealthCheck>("alttext");

Problemen oplossen

Downloaden van modellen is mislukt

Error: Failed to download model files

Oplossingen:

  • Controleer internetconnectiviteit
  • Firewall verifiëren maakt het mogelijk om Hugging Face-downloads te downloaden
  • Zorg ervoor dat ~800MB schijfruimte beschikbaar is
  • Schrijfrechten controleren op ModelPath

Service is nog niet klaar

_imageAnalysis.IsReady // Returns false

Oplossingen:

  • Wacht op modelinitialisatie (1-3 seconden)
  • Logboeken controleren op initialisatiefouten
  • Controleer voldoende geheugen (2GB+)

Alt-tekst van slechte kwaliteit

Oplossingen:

  • Gebruik MORE_DETAILED_CAPTION (standaard)
  • Zorg ervoor dat de invoerafbeeldingen duidelijk zijn
  • Afbeelding controleren is niet te klein of wazig

TagHelper werkt niet

Oplossingen:

  • Verifiëren EnableTagHelper = true
  • Controleren @addTagHelper in _ViewImports.cshtml
  • absolute URL's gebruiken (relatieve paden worden overgeslagen)
  • Controleren AllowedImageDomains configuratie

Toegankelijkheid Beste praktijken

Gegenereerde alt tekst is een startpunt. Voor de beste resultaten:

  1. Evaluatie van de uitvoer AI is niet perfect, controleer de nauwkeurigheid.
  2. Hou het kort. - maximaal 90-100 woorden
  3. Descriptief zijn - omvatten onderwerpen, acties, context
  4. Vermijd redundantie - begin niet met "Afbeelding van..."
  5. Beschouw het doel - alt tekst dient de rol van de afbeelding op de pagina
  6. Gebruik lege alt voor decoratief - ingesteld alt="" voor puur decoratieve afbeeldingen
  7. Zichtbare tekst invoegen - als afbeelding tekst bevat, invoegen

Conclusie

Mostlylucid.LlmAltText brengt AI-aangedreven toegankelijkheid naar uw .NET toepassingen zonder de kosten of privacy zorgen van externe API's. De TagHelper maakt het bijzonder gemakkelijk - gewoon inschakelen en uw <img> tags krijgen automatisch alt tekst.

Het pakket is Unlicense (publiek domein), dus doe ermee wat je wilt.

Middelen

logo

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