Back to "AI- Puarded Alt Text Generation with macimid.llmtText"

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- Puarded Alt Text Generation with macimid.llmtText

Monday, 24 November 2025

Хочете отримати гарний описовий текст для зображень на ваших сайтах або jsut видобути з них текст? mostlylucid.llmalttext Для автоматичного створення високоякісного альт- тексту скористайтеся моделлю Microsoft Floorce- 2, - запущеною на вашому комп' ютері повністю локально, без використання ключів API не потрібно.

Зауваження: тепер мені потрібно оновити цей документ Пакунок nuget Вышел. тут Ви зможете звантажити і скористатися п' ятьма демонстраціями. Я оновлю їх докладними відомостями у найближчі дні.

NuGet Ліцензія: Un license

Вступ

Alt text usist. Screen readers залежить від цього, рейтинги SEO враховують його, і це просто правильно для доступності.

Цей пакунок вирішує проблеми, пов'язані з використанням моделі бачення Microsoft Floorce- 2 - запущеної повністю на вашому комп' ютері, не потрібно ключів API.

Джерело: gitub.com/scottgal/ methlylucid. nuget packages

Проблема

Кожні <img> tag має містити змістовний ltий текст. Але на практиці:

  • Ручне письмо стомливе. - Сотні зображень означає години роботи
  • API API коштує гроші - OpenAI Vision, Clawel тощо. Складається швидко
  • Підтримки конфіденційності - ви, можливо, не бажаєте надсилати зображення до зовнішніх програм API
  • Непослідовна якість - Різні люди пишуть альт- текст по-іншому.

Що, якщо ви могли б створити високоякісний альт- текст автоматично, повністю запущено на вашому власному обладнанні?

Як це працює

Пакунок використовує модель Microsoft Floorce- 2 за допомогою ONNX run time. Ось процесорний канал:

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

Можливості ключів:

  • Локальна виконання - без дзвінків API, без витрат, без конфіденційності
  • ~800МБ модель - Звантажується один раз, кешовано назавжди
  • Декілька типів задач - Короткі підписи, детальні описи, ОРС
  • Класація вмісту - Знає, чи це фото, діаграма, знімки і т.д.

Швидкий запуск

Встановлення

dotnet add package Mostlylucid.LlmAltText

Служби реєстрації

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

Перший запуск завантажує Флоренцію-2 (~800МБ), тоді ви готові йти.

Створити 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 });
    }
}

Декілька джерел вхідних даних

Служба приймає зображення з будь- якого місця - файлів, адрес URL, потоків даних або масивів байтів.

З шляху до файла

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

З URL

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

З потоку

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

З масиву байтів

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

Типи задач: Керування рівнем деталізації

Флоренс- 2 підтримує три режими підписів. Оберіть, на основі ваших потреб:

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

Під час використання:

Д_ д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. |-----------|----------| | CAPTION Дівчата, декоративні зображення, швидкі лапки | DETAILED_CAPTION ♪ Some multimedia, базова доступність ♪ | MORE_DETAILED_CAPTION }Частота доступності, читачі екранів (рекомендовано)}

Розпакування тексту ОРС

Крім того, Флоренція- 2 може видобувати текст з зображень - корисно для знімків екрана, документів і діаграм.

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

Класифікація вмісту

Не всі зображення однакові. Для фотографії потрібен опис тексту alt; документ потребує текстового вмісту. Можливість класифікації допоможе вам належно обробляти кожен з зображень:

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

Як поводитися з різними типами вмісту

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

Довідка щодо типів вмісту

|------|-------------|---------| | Photograph Горішні фото: People, ternes, applications, applications ♪ | Document Text- that контент} PDFs, форми, Styles ♪ | Screenshot applications}UI, веб-сайти, додатки ♪ | Chart Д_ д./ д./ д./ д./ д./ д./ д./ д./ д./ д./ д./ д. | Illustration Передбачайте про те, щоб ви знали, що ви робите, а що ні. | Diagram Д_ д. д. д. д. д. д. д. д. д. д. ст. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. ст. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. д. | Unknown uncellections

Автоматична довідка з текстових міток

Ось де це стає цікавим. За допомогою інструменту довідки TagHelp буде автоматично створювати будь- який текст Alt <img> не вистачає одного теґу - під час відтворення.

Налаштування

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

Зареєструвати довідку з міток у _ViewImports.cshtml:

@addTagHelper *, Mostlylucid.LlmAltText

Як це працює

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

Що обробляється

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

Обмеження доменів

Для безпеки, ви можете обмежити домени, які буде отримано для доменів, з таких доменів:

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

Кечування баз даних

Без кешування всі сторінки, які буде відтворено, відновлюватимуться у текстовому форматі alt. Це повільне і марнотратне відтворення. У сховищі кешу баз даних буде показано посилання на адресу URL зображення.

SQLite (Обсяг робіт)

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

PostgreSQL (Продукція)

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

Довідка щодо налаштування

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

Приклад реального світу: Пакетна обробка

Ось як я використовую його для обробки зображень під час імпортування дописів блогу:

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

Обмірковування швидкодії

Чого сподіватися

Метриця |--------|--------------| ♪ Першу прохід} # (~800 Мб- модель звантаження) ♪ ♪ Mode load} 1-3 секунди ♪ ♪ Per- image process} 500-2000ms} Рекомендуємо використовувати 2GB+} Передбачається, що ця область стане простором: +800МБ для моделей}

Поради для виробництва

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

Інтеграція OpenTelemterry

До пакунка включено вбудоване трасування:

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

Відслідковані діяльності:

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

Перевірка здоров'я

Додати перевірку здоров' я для спостереження за станом моделі:

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

Вирішення проблем

Спроба звантаження моделей зазнала невдачі

Error: Failed to download model files

Вирішення:

  • Перевірити зв' язок з мережею Інтернет
  • Перевірка брандмауера дозволяє захоплювати обличчя
  • Забезпечити наявний простір на диску ~800МБ
  • Позначте права доступу для запису ModelPath

Служба не готова

_imageAnalysis.IsReady // Returns false

Вирішення:

  • Чекати на ініціалізацію моделі (1- 3 секунди)
  • Перевіряти журнал помилок ініціалізації
  • Перевірити достатню пам'ять (2 ГБ+)

Неякісний текст Alt

Вирішення:

  • Користування MORE_DETAILED_CAPTION (типовий)
  • Забезпечити вхідні зображення ясними
  • Перевірити зображення не дуже маленьке або розмите

Допоміжна програма TagHelper не працює

Вирішення:

  • Перевірити EnableTagHelper = true
  • Перевірити @addTagHelper дюймunit description in lists _ViewImports.cshtml
  • Використовувати абсолютні URL (відносні шляхи пропущено)
  • Перевірити AllowedImageDomains налаштування

Найкращі методи доступності

Створений арт- текст є початковою точкою. Найкращі результати:

  1. Переглянути вивід - Комп'ютерний інтелект не ідеальний, перевірте точність
  2. Не перебільшуй. - 90- 100 слів максимум
  3. Будьте описовими - включити теми, дії, контекст
  4. Уникайте надмірності - не починай з "Зображення..."
  5. Розглянемо мету - Alt текст повинен слугувати ролі зображення на сторінці
  6. Використовувати порожню рекламу для декоративності - create alt="" для суто декоративних зображень
  7. Включити видимий текст - якщо зображення містить текст, включення

Висновки

Mostlylucid.LlmAltText заводить потужну доступність комп' ютерного гравця до ваших програм. NET без сторонньої або конфіденційної інформації про зовнішні API. Інструмент довідки Tag робить це дуже простим - просто вмикайте його і ваш комп' ютер <img> Мітки отримують автоматичний альтовий текст.

Пакунок складається з Unscension (публічний домен), отже робіть з ним все, що забажаєте.

Ресурси

logo

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