# AI-Powered Alt Text Generation con perlopiùlucid.llmlltText

Vuoi ottenere bel, descrittivo alt testo per le immagini sui vostri siti o jsut estrarre testo da loro? `mostlylucid.llmalttext` utilizza il modello di linguaggio di visione Florence-2 di Microsoft per generare testo alt di alta qualità automaticamente - in esecuzione interamente localmente sulla vostra macchina, nessuna chiave API richiesta.

> Nota: Ho bisogno di aggiornare questo documento ora il [pacchetto nuget ](https://www.nuget.org/packages/Mostlylucid.LlmAltText)è fuori. Se si guarda [qui](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.AltText.Demo) Lei finirà un sito di dimostrazione nifty che Lei può scaricare e usare. Lo aggiornerò con i dettagli nei prossimi giorni.

<datetime class="hidden">2025-11-24T10:00</datetime>

<!-- category -- ASP.NET, Accessibility, AI, NuGet, Florence-2, Image Processing -->
[![NuGetCity name (optional, probably does not need a translation)](https://img.shields.io/nuget/v/mostlylucid.llmaltText.svg)](https://www.nuget.org/packages/mostlylucid.llmalttext) [![Licenza: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](http://unlicense.org/)

# Introduzione

Alt testo conta. I lettori di schermo dipendono da esso, fattori di classifica SEO, ed è semplicemente la cosa giusta da fare per l'accessibilità. Ma la scrittura di un buon testo alt per centinaia di immagini? Ecco dove la maggior parte di noi non riescono.

Questo pacchetto risolve il problema utilizzando il modello di linguaggio di visione Florence-2 di Microsoft - eseguito interamente localmente sulla macchina, nessuna chiave API richiesta.

**Codice sorgente:** [github.com/scottgal/mostlylucid.nugetpackages](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.LlmAltText)

[TOC]

# Il problema

Ogni `<img>` tag dovrebbe avere un testo alt significativo. Ma in pratica:

- **La scrittura manuale è noiosa** - centinaia di immagini significano ore di lavoro
- **API AI costano denaro** - OpenAI Vision, Claude, ecc.
- **Questioni relative alla tutela della vita privata** - potresti non voler inviare immagini ad API esterne
- **Qualità inconsistente** - persone diverse scrivono il testo in modo diverso

Che cosa succede se si può generare il testo di alta qualità automaticamente, in esecuzione interamente sul proprio hardware?

# Come funziona

Il pacchetto utilizza il modello Florence-2 di Microsoft tramite runtime ONNX. Ecco la pipeline di elaborazione:

```mermaid
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
```

**Caratteristiche principali:**

- **Esecuzione locale** - nessuna telefonata API, nessun costo, nessun problema di privacy
- **~800MB modello** - download una volta, cached per sempre
- **Tipi di attività multipli** - brevi didascalie, descrizioni dettagliate, OCR
- **Classificazione dei contenuti** - sa se è una foto, un grafico, uno screenshot, ecc.

# Avvio rapido

## Installazione

```bash
dotnet add package Mostlylucid.LlmAltText
```

## Servizi di registrazione

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

La prima esecuzione scarica il modello Florence-2 (~800MB), poi sei pronto a partire.

## Genera testo Alt

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

# Sorgenti multiple di input

Il servizio accetta immagini da qualsiasi luogo - file, URL, flussi o array di byte.

## Dal percorso del file

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

## Da URL

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

## Da flusso

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

## Da Byte Array

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

# Tipi di attività: Controllo del livello di dettaglio

Florence-2 supporta tre modalità di didascalia. Scegli in base alle tue esigenze:

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

**Quando usare ciascuna:**

| Tipo di operazione | Migliore per |
|-----------|----------|
| `CAPTION` | Miniature, immagini decorative, suggerimenti rapidi |
| `DETAILED_CAPTION` | Social media, accessibilità di base |
| `MORE_DETAILED_CAPTION` | Piena accessibilità, lettori dello schermo (raccomandati) |

# Estrazione del testo OCR

Firenze-2 può anche estrarre testo da immagini - utili per screenshot, documenti e grafici.

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

# Classificazione del tipo di contenuto

Non tutte le immagini sono uguali. Una fotografia ha bisogno di un testo descrittivo; un documento ha bisogno del suo contenuto di testo. La funzione di classificazione ti aiuta a gestire ciascuno in modo appropriato:

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

## Gestione di diversi tipi di contenuto

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

## Riferimento del tipo di contenuto

| Tipo | Descrizione | Esempio |
|------|-------------|---------|
| `Photograph` | Foto del mondo reale | Persone, paesaggi, prodotti |
| `Document` | Contenuti pesanti per testo | PDF, moduli, articoli |
| `Screenshot` | Cattura software | UI, siti web, applicazioni |
| `Chart` | Visualizzazioni dati | Grafici, grafici a torta, tabelle |
| `Illustration` |Contenuto di disegno |Opere, cartoni animati, icone |
| `Diagram` | Disegni tecnici | Carrelli di flusso, UML, schemi |
| `Unknown` | Non classificati | Casi di bordi |

# L'Auto Alt Text TagHelper

Qui è dove diventa interessante. Il TagHelper genera automaticamente il testo dell'alt per qualsiasi `<img>` tag mancante uno - al momento del rendering.

## Configurazione

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

Registrare il tagHelper in `_ViewImports.cshtml`:

```cshtml
@addTagHelper *, Mostlylucid.LlmAltText
```

## Come funziona

```mermaid
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
```

## Che cosa viene elaborato

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

## Restrizioni di dominio

Per la sicurezza, è possibile limitare i domini che il TagHelper prenderà da:

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

# Caching database

Senza cache, ogni rendering di pagina rigenererebbe il testo alt. Questo è lento e sprecoso. Il deposito della cache del database risulta chiavi in mano dall'URL dell'immagine.

## SQLite (Sviluppo)

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

## PostgreSQL (produzione)

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

# Riferimento di configurazione

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

# Esempio di Real-World: Elaborazione batch

Ecco come lo uso per elaborare le immagini durante l'importazione dei post del blog:

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

# Considerazioni sulle prestazioni

## Cosa aspettarsi

| Metric | Tipic Value |
|--------|--------------|
| Prima esecuzione | Più lento (download del modello ~800MB) |
| Carico del modello | 1-3 secondi |
| Lavorazione per immagine | 500-2000ms |
| Uso della memoria | 2GB+ raccomandato |
| Spazio su disco | ~ 800MB per i modelli |

## Consigli per la produzione

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

# Integrazione OpenTelemetry

Il pacchetto include il tracciamento integrato:

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

**Attività rintracciate:**

- `llmalttext.generate_alt_text`
- `llmalttext.extract_text`
- `llmalttext.analyze_image`
- `llmalttext.classify_content_type`

# Controlli sanitari

Aggiungi un controllo dello stato di salute per monitorare lo stato del modello:

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

# Risoluzione dei problemi

## Modello di download non riuscito

```
Error: Failed to download model files
```

**Soluzioni:**

- Controllare la connettività internet
- Verifica firewall consente il download di Hugging Face
- Assicurate ~800MB di spazio su disco disponibile
- Controlla i permessi di scrittura su `ModelPath`

## Servizio non pronto

```csharp
_imageAnalysis.IsReady // Returns false
```

**Soluzioni:**

- Attendere l'inizializzazione del modello (1-3 secondi)
- Controlla i registri per gli errori di inizializzazione
- Verificare memoria sufficiente (2GB+)

## Testo Alt di scarsa qualità

**Soluzioni:**

- Uso `MORE_DETAILED_CAPTION` (predefinito)
- Assicurarsi che le immagini in ingresso siano chiare
- Controllare l'immagine non è troppo piccolo o sfocato

## TagHelper non funzionante

**Soluzioni:**

- Verifica `EnableTagHelper = true`
- Controlla `@addTagHelper` in `_ViewImports.cshtml`
- Usa URL assoluti (i percorsi relativi sono saltati)
- Controlla `AllowedImageDomains` configurazione

# Migliori pratiche di accessibilità

Il testo alt generato è un punto di partenza. Per i migliori risultati:

1. **Rivedere l'output** - AI non è perfetto, verificare l'accuratezza
2. **Tienilo conciso.** - 90-100 parole massimo
3. **Essere descrittivo** - includere soggetti, azioni, contesto
4. **Evitare la ridondanza** - Non cominciare con "Immagine di..."
5. **Considera lo scopo** - alt testo dovrebbe servire il ruolo dell'immagine sulla pagina
6. **Utilizzare alt vuoto per la decorazione** - set `alt=""` per immagini puramente decorative
7. **Includi testo visibile** - se l'immagine contiene testo, includerlo

# Conclusione

`Mostlylucid.LlmAltText` porta l'accessibilità AI-powered alle vostre applicazioni .NET senza il costo o problemi di privacy di API esterne. Il TagHelper rende particolarmente facile - basta abilitare e il vostro `<img>` tags ottiene testo automatico alt.

Il pacchetto è Unlicense (public domain), quindi fai quello che vuoi.

## Risorse

- **NuGet:** [Per lo più Lucid.LlmAltText](https://www.nuget.org/packages/Mostlylucid.LlmAltText)
- **Fonte:** [github.com/scottgal/mostlylucid.nugetpackages](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.LlmAltText)
- **Problemi:** [Problemi GitHub](https://github.com/scottgal/mostlylucidweb/issues)
- **Florence-2:** [Modello di linguaggio di visione di Microsoft](https://huggingface.co/microsoft/Florence-2-base)