Back to "AI-Generation d'un texte Alt à puissance avec mostlylucid.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-Generation d'un texte Alt à puissance avec mostlylucid.llmlltText

Tuesday, 25 November 2025

Vous voulez obtenir un nice, texte alt descriptif pour les images sur vos sites ou jsut extraire du texte de ces images? mostlylucid.llmalttext utilise le modèle de langage visuel Microsoft's Florence-2 pour produire automatiquement un texte alt de qualité élevée - M SK3 qui fonctionne entièrement localement sur votre machine

Note: Je dois mettre à jour ce doc maintenant Nuget package est hors. Si vous regardez ici vous' je ferai fonctionner un bon site de démonstration que vous pouvez télécharger et utiliser.

NuGet Licence: Non-licence

Introduction

Le texte alt est important. Les lecteurs d’écran dépendent de lui, Les classements SEO l’influencent sur ce facteur , et c’est simplement la bonne chose à faire pour assurer l’accessibilitéM SK4 Mais il faut écrire un bon texte alt pour des centaines d'images.

Ce paquet résout ce problème en utilisant le modèle de langage visuel Microsoft' Florence-2 - qui fonctionne entièrement localement sur votre machine

Code de source: github.com /scottgal/mostlylucidM SK3nugetpackages

Le problème

Tous les <img> tag devrait avoir un texte alt significatif. Mais dans la pratique:

  • La rédaction manuelle est acharnée - Des centaines d'images signifient des heures de travail
  • Les API de l'AI coûtent cher - OpenAI Vision , Claude, etcM SK3 ajouter rapidement
  • Préoccupations liées à la protection des renseignements personnels - vous ne souhaitez peut-être pas envoyer des images aux API externes
  • Qualité incohérente - différentes personnes écrivent le texte alt différemment

Que se passerait-il si vous possédais générer automatiquement un texte alt de qualité élevée-qui fonctionne entièrement sur votre propre matériel?

Comment cela fonctionne

Le paquet utilise le modèle de Microsoft's Florence-2 via ONNX runtime . HereMSC3s the processing pipelineM SK4

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

Principales caractéristiques:

  • Exécution locale - aucun appel à l’APIM SK1 aucun coût , aucune préoccupation en matière de protection des renseignements personnels
  • Modèle ~800MB - télécharge une fois, cache pour toujours
  • Types de tâche multiples - sous-titres succincts , descriptions détailléesM SK2 OCR
  • Classification du contenu - sait s’il est une photo ' graphe

Démarrage rapide

Installation

dotnet add package Mostlylucid.LlmAltText

Services de registre

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

Le premier essai télécharge le modèle Florence-2 (~800MB), puis vousMSC5vous êtes prêts à partirM SK6

Créer un texte Alt

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

Sources d'entrée multiples

Le service accepte les images de n'importe où - fichiers, URLs , fluxM SK3 ou tableaux de bytesMSC4

À partir du chemin de fichier

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

De l'URL

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

De l'écoulement

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

De l'Arraye de Bytes

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

Types de tâche: Niveau de détail de contrôle

Florence-2 appuie trois modes de captioningM SK1 Choisissez selon vos besoins:

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

Quand utiliser chacune:

Type de tâche Le meilleur pour
CAPTION Diagrammes d'images miniaturesM SK1 images décoratives, conseils rapides sur les outils
DETAILED_CAPTION Médias sociauxM SK1 accessibilité de base
MORE_DETAILED_CAPTION pleine accessibilitéM SK1 lecteurs d'écran ( recommandée

Extraction de texte OCR

Florence-2 peut aussi extraire du texte des images M SK1 utile pour les screenshots, documentsMST3 et diagrammesMSS4

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

Classification du type de contenu

Les images ne sont pas toutes les mêmes. Une photographie a besoin d'un texte alt descriptif; un document a besoin du contenu textuel de son objetM SK2 La fonction de classification vous aide à traiter chacune de ces images de façon appropriée :

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

Gestion des différents types de contenu

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

Type de contenu Référence

Type Description MSC2 Exemple SMC3
Photograph Photo réelleM SK1photos du monde Personnes, paysagesMSC4 produits
Document TexteM SK1 Contenu volumineux PDFs, formulaires
Screenshot Captures de logiciels UIM SK2 sites Web, applications
Chart Visualisations des données
Illustration Contenu dessiné Travaux d'artM SK2 caricatures, icones
Diagram Des dessins techniques Des diagrammes d'écoulement
Unknown Non classé Cases à bord SSK2

L'Auto Alt Text TagHelper

Voici's où il devient intéressant. Le TagHelper génère automatiquement le texte alt pour n'importe quel <img> tag manquant un - au moment de la traduction.

Mise en place

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

Inscrire le TagHelper dans _ViewImports.cshtml:

@addTagHelper *, Mostlylucid.LlmAltText

Comment cela fonctionne

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

Ce qui est traité

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

Restrictions sur le domaine

Pour la sécurité, vous pouvez restreindre les domaines que le TagHelper fetchera de:

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

Cache des bases de données

Sans cache, chaque traduction de page régénérerait le texte alt. Que ' est lente et irrégulièreM SK3 Le cache de la base de données stocke les résultats saisis par l'image URLMSC4

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

Référence de configuration

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

Exemple mondiale: Traitement en lots réels

Voici la façon dont je l’utilise pour traiter les images lors de l’importation des articles sur le blog:

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

Considérations relatives au rendement

Ce que l'on attend

Metrique Valeur typique
Démarrage Moteur plus lente ~800 téléchargement du modèleMBM SK3 M
Charge de modèle 1-3 secondes M
ParM SK1traitement d'images 500-2000ms S
Utilisation de la mémoire 2GBMSC3 recommandée S
espace de disques MSC2MB pour les modèles SMC3

Conseils pour la production

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

Intégration de la télémétrie ouverte

Le paquet inclut le traçage intégré-:

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

Activités suivies:

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

Examens de santé

Ajouter un contrôle de santé pour surveiller l'état du modèle:

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

Défaut de télécharger le modèle

Error: Failed to download model files

Solutions:

  • Vérifier la connectivité à Internet
  • Vérifier le pare-feu permet de télécharger Hugging Face
  • Assurer la disponibilité de l'espace ~800MB sur le disque
  • Vérifier les permissions d'écriture sur ModelPath

Le service n'est pas prêt

_imageAnalysis.IsReady // Returns false

Solutions:

  • attendre l'initialisation du modèle (1-3 secondes)
  • Vérifier les registres des erreurs d'initialisation
  • Vérifier la mémoire suffisante (2GB+)

La qualité médiocre du texte Alt

Solutions:

  • Utilisation MORE_DETAILED_CAPTION (default)
  • Assurez-vous que les images d'entrée sont claires
  • Vérifier si l’image n’est pas trop petite ou floue

L'aide-étiquette ne fonctionne pas

Solutions:

  • Vérifier EnableTagHelper = true
  • Vérifier @addTagHelper dans _ViewImports.cshtml
  • Utiliser des URL absolues (les voies relatives sont passées par erreur)
  • Vérifier AllowedImageDomains Configuration

Pratiques exemplaires en matière d'accessibilité

Le texte alt généré est un point de départ. Pour obtenir les meilleurs résultats:

  1. Examiner le résultat - L'AI n'est pas parfaiteM SK1t perfect, vérifier l'exactitude
  2. Gardez-le concis - 90-100 mots maximum
  3. Être descriptif - inclure les sujets, actionsM SK2 contexte
  4. Éviter la redondance - donM SK1 ne débute pas avec "Image de..."
  5. Examiner le but - le texte alt doit servir à l’image ' du rôle sur la page
  6. Utiliser alt vide pour la décoration - ensemble alt="" pour des images purement décoratives
  7. Inclure le texte visible - si l'image contient du texte, y inclure

Conclusion

Mostlylucid.LlmAltText permet une accessibilité -améliorée de l’AI à vos applications .NET sans les préoccupations liées au coût ou à la protection des renseignements personnels des API externes. Le TagHelper rend tout particulièrement facile <img> tags gain automatic alt text.

Le paquet est Unlicense (domain public), donc faites tout ce que vous voulez avec luiM SK2

Ressources

logo

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