AI-Powered Alt Text Generation with mostlylucid.llmlltText (Svenska (Swedish))

AI-Powered Alt Text Generation with mostlylucid.llmlltText

Tuesday, 25 November 2025

//

11 minute read

Vill du få trevliga, beskrivande alttext för bilder på dina webbplatser eller jsut extrahera text från dem? mostlylucid.llmalttext använder Microsoft's Florence

Nota: Jag behöver uppdatera den här dokumenten nu nuget package är ute. Om du tittar här du' kommer att få reda på en häftig demo-sida som du kan ladda ner och använda

NuGet Licensen : Olicenctioner

Inleiding

Alttext spelar roll. Att skärmen-readerer är beroende av det , SEO-Rankingsfaktorerna påverkar det i, och det är helt enkelt det rätta att göra för tillgänglighet, . Men att skriva bra alttext för hundratals bilder,? Det är det som ' är där de flesta av oss misslyckas med.

Det här paketet löser problemet med hjälp av Microsoft's Florence

källkod: github.comM SK1scottgal/mostlylucid .nugetpackages

Problemet

Varje <img> tag skulle ha betydelsefull alt text. Men i praktiken:

  • Handskrivande är tråkigt - hundratals bilder innebär timmars arbete
  • AI APIs kostar pengar - OpenAI Vision
  • Bekymmer om privatliv - du kanske inte vill skicka bilder till externa APIs
  • Inkonsistent kvalitet - olika människor skriver alttext på olika sätt

Tänk om du kunde generera hög kvalitet alttext automatiskt på din egen hårdvara

Hur det fungerar

Paketet använder Microsofts modell, ', Florences modell och -2 via ONNX-runtimen.

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

Nyckelfunktionen:

  • Lokalt utförande - inga API-sändningar , inga kostnader
  • ~800MB modell - ladda ned en gång, kastars för alltid
  • Flera typer av uppgifter - korta captionar , detaljerade beschreibunger, OCR
  • Inhoudsklassificering - vet om det är ett foto

Vinnig Start

Installation

dotnet add package Mostlylucid.LlmAltText

Register Services

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

Det är det. Den första versionen laddar ner Florences modell.

Generera Alt Text

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 });
    }
}

Flera inmatningskällor

Servicen accepterar bilder från var som helst - filer , URLs M SK2 strömmar , eller bytskiffer

Från Lêerpfad

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

Från URL

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

Från ström

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

Från Byte Array

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

Tasktyper: Kontrollspecifika nivåer

Florence-2 supporterar tre caption-modi . Välj utifrån dina behov:

// 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."

När man ska använda var och en

Uppgiftstyp bäst för
CAPTION Tappnalar , dekorativa bilder, snabb verktygstips
DETAILED_CAPTION Sociala medier
MORE_DETAILED_CAPTION Den fulla tillgänglighetenM SK1 skärmar läsare ( tillämpt

OCR Textuttvingning

Florence-2 kan också extrahera text från bilder | - användbar för bildskärmdumpar |, | dokument | МSK3 | och diagram

// 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}");

innehållstyp klassificering

Alla bilder är inte likadana. Ett fotografi behöver deskriptiv alttext; ett dokument behöver dess textinnehåll

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}");

Att hantera olika typer av innehåll

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;
}

innehållstyp referens

Typ Beskrywing exempel
Photograph VerkligM SK1 världsbildar Människor, landskap
Document Text
Screenshot Oprogramskapande ♫ ♫ UI ♫
Chart Datavisualiseringar Grafiska , tallriksdiagram МSK3 tabeller
Illustration Tecknad innehåll Konstverk, tecknade bilderM SK3 ikoner
Diagram tekniska ritningar Flowcharts , UML
Unknown Oklassificerad Kanter vid kanten

Det automatiska Alt Text-TagHelper

Här' är det som blir intressant. TagHelper genererar automatiskt alttext för alla <img> tag saknade ett - vid rendertid.

Konfiguration

// 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();

Registrera taghjältaren i _ViewImports.cshtml:

@addTagHelper *, Mostlylucid.LlmAltText

Hur det fungerar

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

Vad som processeras

<!-- 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" />

Domainbegränsningar

För säkerhet, kan du begränsa vilka domän som TagHelper kommer att få fram från:

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

Databas Caching

Utan kassering, skulle varje skriftskap återskapa alttexten. Det ' var långsamt och slösaktigtM SK3 Databasens kassrar sparar resultat som är krypterade av en bild-URL

SQLite (Development)

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

PostgreSQL (Production)

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

Konfigurationsreferens

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;
});

Verklig-World Example: Batch Processing

Här är hur jag använder den för att processa bilder när jag importerar bloggposter.

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";
    }
}

Tillvägagångspunkter

Vad man förväntar sig

Metrik Typiskt värde
Först ut långsammare ~800 MB modelldownload
Modelllast 1-3 sekunder МSK3
PerM SK1bildbehandlande 500-2000ms
Membrans tillämpning 2 GB {\displaystyle }
Disk utrymme ~800MB för modeller M

Tipps för produktion

// 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
}

OpenTelemetry integration

Paketet inkluderar byggt-inspårning:

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

spårade aktiviteter:

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

Hälsakontroller

Lägg till en hälsokontroll för att övervaka modellens status:

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");

Troubleshooting

Modelldownloading misslyckades

Error: Failed to download model files

Lösningar:

  • kolla internetuppkoppling
  • Verifiera firewall som tillåter Hugging Face -downloads
  • Försäkra att ~800MB diskytan är tillgänglig
  • Bevestig att skriva tillstånd på ModelPath

Service är inte redo

_imageAnalysis.IsReady // Returns false

Lösningar:

  • Vänta till modellinitialisering (1-3 sekunder
  • Kontrollera protokoll för initialiseringsfehler
  • Verifiera tillräckligt med minne (2GB+)

dålig kvalitet Alt Text

Lösningar:

  • Använda MORE_DETAILED_CAPTION (default)
  • Försäkra att inmatningsbilderna är tydliga
  • Prüfa att bilden är "'", inte för liten eller suddig

TagHelper inte fungerar

Lösningar:

  • Verifiera EnableTagHelper = true
  • Kontroller @addTagHelper i _ViewImports.cshtml
  • Använd absoluta URLs (relativa vägar är hoppade över
  • Kontroller AllowedImageDomains Konfiguration

Möjligheter till tillgänglighet

Genererad alttext är en utgångspunkt

  1. Omvärdera utgången - AI är inte perfekt
  2. Håll det kort - 90-100 ord max
  3. Var deskriptiv - inkluderar subjekter , handlingar
  4. undvika överskott - donM SK1 inte börja med "Image of..."
  5. Tänk på meningen - alt text borde tjäna bilden 's roll på sidan
  6. Använd tom alt för dekorativa - uppsättning alt="" för rent dekorativa bilder
  7. Inbegripa synlig text - om bilden innehåller text

Slutsatsen

Mostlylucid.LlmAltText tar med sig AI- kraftfull tillgång till dina | .NET-applikationer utan kostnads- eller privatlivsproblem från externa APIs |. TagHelper gör det speciellt enkelt | <img> tag får automatic alt text.

Paketet är Licenslös (public domain), så gör vad du vill med det

resurser

Finding related posts...
logo

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