В Частина 1 Я показав сирову трубу. МСК0. Ручно завантажуючи моделі. МSK1. Пишаючи токенізер. ММК2. Використовуючи набір ONNX. МКС3. І розшифровуючи BIO-теги вручну. ММСК4. Освітній. МПСК5. Але багато водопроводів, щоб зробити все правильно. МУСК6.
Тепер це - пакет NuGet Один ряд установок, нуль загрузок моделей - все автоматизовано -завантаження на перший разM SK2
Nota: Цей пакет є спрощеним, фокусованим інструментом для видобутку тексту та об 'єктів з зображень будь-що (фотографіїM SK1 документи МSK2 скриншоти , ручний малюнокМSK4 анімованіGIFи і навіть відео) з неяскравим співпадіннямMSC6 консенсус OCRMST7 та структурований видобутокМST8 перевірте прозораРАГ де проходить виробництво-швидкісної версії цього трубопроводуM SK1
Перед тим, як зануритися в це слово:
.onnx файл, локальноTesseract ефективний для чистого тексту dokumentu, але він потрапив на шумні фотографіїМSK1 низькийM SK2 контрастні скани, і змішені MSC4 сцена МСК5 текстМ СК6 зображенняMСК7 Він також зупиняється на сирому тексті МСК8 ви все ще потребуєте додаткового коду, щоб перетворити цей текст на структуровані об 'єкти, які ви дійсно можете використовуватиMSК9
Цей пакет вирішує ці прогалини.
AddOcrNer() і ви закінчилиflowchart LR
subgraph Part1["Part 1: Manual"]
M1[Download models]
M2[Write tokenizer]
M3[Wire ONNX]
M4[BIO decode]
end
subgraph Part2["Part 2: NuGet Package"]
N1["AddOcrNer()"]
N2[Auto-download]
N3[Preprocessing]
N4[Florence-2]
N5[CLI Tool]
end
Part1 -->|"packaged into"| Part2
style N1 stroke:#090,stroke-width:3px
style N2 stroke:#090,stroke-width:3px
style N3 stroke:#f60,stroke-width:3px
style N4 stroke:#f60,stroke-width:3px
style N5 stroke:#f60,stroke-width:3px
Частина 1 була освітньою - розуміння того, що робить кожна частина МSK2 Część МSK3 є практичною \ - використання її без роздумів про внутрішні речі \ МSK5
dotnet add package Mostlylucid.OcrNer
І AddOcrNer() метод розширення записує все : OCR, NERM SK2 об 'єднаний трубний кабель МSK3 Флоренція МСК4 зоріобачення М СК5 модельний завантажувач M СК6 і пристрій для обробки зображення М S К 7 Все як одинокі тони M S К 8 всі лінивіші М ็ С К 9 зачаровані M ็ S К 10
Тут - МСК0 - це справжній регистрационний код ServiceCollectionExtensions.cs:
// Option 1: From appsettings.json (reads the "OcrNer" section)
builder.Services.AddOcrNer(builder.Configuration);
// Option 2: Inline configuration
builder.Services.AddOcrNer(config =>
{
config.EnableOcr = true;
config.TesseractLanguage = "eng";
config.MinConfidence = 0.5f;
});
МSK0 - це він. МSK1 - Ніхто не завантажує моделі, МSK2 - немає файлових маршрутів, , - немає ONNX підключення, МСК4 - під капюшоном, MСК5 AddOcrNer() реєструє ці послуги:
// From ServiceCollectionExtensions.cs - what gets registered
services.AddSingleton<ModelDownloader>(); // Auto-downloads models on first use
services.AddSingleton<ImagePreprocessor>(); // ImageSharp-based image enhancement
services.AddSingleton<INerService, NerService>(); // BERT NER from text
services.AddSingleton<IOcrService, OcrService>(); // Tesseract OCR from images
services.AddSingleton<IOcrNerPipeline, OcrNerPipeline>(); // Combined OCR + NER
services.AddSingleton<IVisionService, VisionService>(); // Florence-2 vision
{
"OcrNer": {
"EnableOcr": true,
"TesseractLanguage": "eng",
"MinConfidence": 0.5,
"MaxSequenceLength": 512,
"ModelDirectory": "models/ocrner",
"Preprocessing": "Default"
}
}
Ось реальний OcrNerConfig поділити ці карти на:
// From OcrNerConfig.cs
public class OcrNerConfig
{
public string ModelDirectory { get; set; } =
Path.Combine(AppContext.BaseDirectory, "models", "ocrner");
public bool EnableOcr { get; set; } = true;
public string TesseractLanguage { get; set; } = "eng";
public int MaxSequenceLength { get; set; } = 512;
public float MinConfidence { get; set; } = 0.5f;
public string NerModelRepo { get; set; } = "protectai/bert-base-NER-onnx";
public PreprocessingLevel Preprocessing { get; set; } = PreprocessingLevel.Default;
}
У всіх настроях є розумні початкові параметри. Ви можете закинути весь розділ і все працюєM SK1
І Preprocessing опція контролює покращення зображення перед OCR:
| Wartość МSK1 Що це робить МSK2 Коли використовувати | ||
|---|---|---|
None |
Жодного попереднього обробки МSK1 Зображення вже оптимізовані МSK2 | |
Minimal |
Тільки Grayscale | Чисті скани МSK2 |
Default |
Грейова шкала МSK1 контраст МSK2 острів | Більшість образів M( запропоновані |
Aggressive |
Сильний контраст МSK1 острівніше МSK2 збільшення | Slikи поганої якості MSК4 |
Пакет записує чотири послуги, кожен корисний незалежно від іншогоM SK1 Виберіть той, що підходить для вашого призначення - там ' немає потреби завантажувати ФлоренціюMSC4 якщо все, що вам потрібно - це NER з текстуМSK5
flowchart TD
subgraph Services
NER["INerService<br>Text → Entities"]
OCR["IOcrService<br>Image → Text"]
PIPE["IOcrNerPipeline<br>Image → Entities"]
VIS["IVisionService<br>Image → Caption"]
end
OCR --> PIPE
NER --> PIPE
style PIPE stroke:#090,stroke-width:3px
style VIS stroke:#f60,stroke-width:3px
Головним принципом є ефективність: вибрати найлегший інструмент, який виконує цю функцію . Не завантаження МSK2 модель візуалізації МSK3 МБ, коли OCR-мобіль M SK4 Мб буде виконувати свою функцію
| Obsługа МSK1 Що він робить МSK2 розмір моделі | Швидкість мSK4 Використовуйте, коли | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
INerService |
BERT NER з тексту | МSK1 | ~430 | MB | ||||||
IOcrService |
Tesseract OCR з зображеннях | МSK2MB МSK3 ♫ ♫ ~100ms ♫ МSK5 Вам потрібен текст із сканування документів ♫, скриншоти ♫ | ||||||||
IOcrNerPipeline |
ОCR, потім NER в одному дзвінку МSK1 Обидві моделі МSK2 ~150ms M | У вас є зображення і хочете об 'єкти в один крок МСК5 | ||||||||
IVisionService |
ФлоренціяM SK1 субтитри МSK2 ОКР МSK3 ~450 МБ | 5 | 6 | 7 | Вам потрібно розуміти зображення | МSK8 | не просто читати текст |
Якщо у вас вже є текст ( з PDFs , бази даних МSK2 вхід користувача M SK3 ви можете використовувати NER напрямуМSK4 це найшвидший шлях МСК5 без OCR МСК6 без обробки зображень
І INerService інтерфейс простий - один метод
// From INerService.cs
public interface INerService
{
Task<NerResult> ExtractEntitiesAsync(string text, CancellationToken ct = default);
}
Тут' як його використовувати в своїй власній сферіM SK1
public class MyService
{
private readonly INerService _nerService;
public MyService(INerService nerService)
{
_nerService = nerService;
}
public async Task ProcessDocumentAsync(string text)
{
var result = await _nerService.ExtractEntitiesAsync(text);
foreach (var entity in result.Entities)
{
// entity.Label: "PER", "ORG", "LOC", or "MISC"
// entity.Text: "John Smith"
// entity.Confidence: 0.9996
// entity.StartOffset / EndOffset: character positions in the source
}
}
}
Результати моделей прості:
// From NerResult.cs / NerEntity.cs
public class NerResult
{
public string SourceText { get; init; } = string.Empty;
public List<NerEntity> Entities { get; init; } = [];
}
public class NerEntity
{
public string Text { get; init; } = string.Empty; // "John Smith"
public string Label { get; init; } = string.Empty; // "PER", "ORG", "LOC", "MISC"
public float Confidence { get; init; } // 0.0 to 1.0
public int StartOffset { get; init; } // Where in the source text
public int EndOffset { get; init; } // End position (exclusive)
}
Перший дзвінок завантажує модель BERT NER (~430MBM SK1 з HuggingFace. Наступні дзвінки використовують зашифровану модель
Для зображеннях, труба об 'єднує підготування, OCRM SK2 і NER в одному wywołaнніMSC3 IOcrNerPipeline об 'єднує IOcrService і INerService:
// From OcrNerPipeline.cs - the actual pipeline code
public async Task<OcrNerResult> ProcessImageAsync(string imagePath, CancellationToken ct = default)
{
// Step 1: OCR (includes preprocessing automatically)
var ocrResult = await _ocrService.ExtractTextAsync(imagePath, ct);
if (string.IsNullOrWhiteSpace(ocrResult.Text))
return new OcrNerResult
{
OcrResult = ocrResult,
NerResult = new NerResult { SourceText = string.Empty }
};
// Step 2: NER on extracted text
var nerResult = await _nerService.ExtractEntitiesAsync(ocrResult.Text, ct);
return new OcrNerResult
{
OcrResult = ocrResult,
NerResult = nerResult
};
}
Використовуючи його:
var pipeline = serviceProvider.GetRequiredService<IOcrNerPipeline>();
var result = await pipeline.ProcessImageAsync("invoice.png");
// What OCR found
var text = result.OcrResult.Text; // The full extracted text
var confidence = result.OcrResult.Confidence; // 0.0 to 1.0
// What NER found in that text
foreach (var entity in result.NerResult.Entities)
{
// [PER] John Smith, [ORG] Microsoft, [LOC] Seattle...
}
flowchart LR
IMG[Image bytes]
PRE["ImageSharp<br>Preprocess"]
TESS["Tesseract<br>OCR"]
TOK["WordPiece<br>Tokenize"]
BERT["BERT NER<br>ONNX"]
ENT[Entities]
IMG --> PRE
PRE --> TESS
TESS --> TOK
TOK --> BERT
BERT --> ENT
style PRE stroke:#f60,stroke-width:3px
style BERT stroke:#f60,stroke-width:3px
Частина 1 мала необроблені дзвінки Tesseract . В praktyce, як Tesserac, так і FlorenceM SK3 працюють краще з передрозробленими зображеннямиMSC4 Передрозробка по замовчуванню але цілком опціонально - ви можете вимкнути його з Preprocessing = "None" в конфігурації або --preprocess none на CLI.
І ImagePreprocessor використання Зображення (pure C
// From ImagePreprocessor.cs - the actual preprocessing steps
public byte[] Preprocess(byte[] imageBytes, PreprocessingOptions? options = null)
{
options ??= PreprocessingOptions.Default;
using var image = Image.Load<Rgba32>(imageBytes);
image.Mutate(ctx =>
{
// Step 1: Upscale small images (Tesseract wants 300+ DPI equivalent)
if (options.EnableUpscale && (image.Width < options.MinWidth || image.Height < options.MinHeight))
{
var scale = Math.Max(
(float)options.MinWidth / image.Width,
(float)options.MinHeight / image.Height);
scale = Math.Min(scale, options.MaxUpscaleFactor);
ctx.Resize((int)(image.Width * scale), (int)(image.Height * scale),
KnownResamplers.Lanczos3);
}
// Step 2: Grayscale (single channel = faster, more accurate)
if (options.EnableGrayscale)
ctx.Grayscale();
// Step 3: Contrast boost (text stands out from background)
if (options.EnableContrast && options.ContrastAmount != 1.0f)
ctx.Contrast(options.ContrastAmount);
// Step 4: Sharpen (crisp character edges)
if (options.EnableSharpen)
ctx.GaussianSharpen(options.SharpenSigma);
});
using var ms = new MemoryStream();
image.SaveAsPng(ms); // PNG = lossless, no additional artifacts
return ms.ToArray();
}
Три пресети вбудовані в. PreprocessingOptions клас визначає їх:
// From ImagePreprocessor.cs
public static PreprocessingOptions Default => new(); // Grayscale + 1.5x contrast + sharpen
public static PreprocessingOptions Minimal => new() // Grayscale only
{
EnableContrast = false,
EnableSharpen = false,
EnableUpscale = false
};
public static PreprocessingOptions Aggressive => new() // For poor quality images
{
ContrastAmount = 1.8f,
SharpenSigma = 1.5f,
MinWidth = 1024,
MinHeight = 768,
MaxUpscaleFactor = 4.0f
};
| Упередбачуваний МSK1 Коли використовувати МSK2 Що це робить | ||
|---|---|---|
Default |
Більшість образів МSK1 Грейова шкала МSK2 1.5 x контраст M+ остришайте світло МСК5 | |
Minimal |
Чисті скани | тільки в чорних діапазонах МSK2 |
Aggressive |
Неякісні фотографії МSK1 МSK2x контраст + жорсткий зустріч MSК4 більший масштаб МСК5 |
Флоренція-2 - це зовсім інший підхід від ТеsseractM SK1, де Tesseract - це спеціалізований OCR-аналізатор, який читає текст символ за символом. модель зору що розуміє ціле зображення. - об 'єкти , сцени МSK2 люди, , і текст
// From IVisionService.cs
public interface IVisionService
{
Task<VisionCaptionResult> CaptionAsync(string imagePath, bool detailed = true,
CancellationToken ct = default);
Task<VisionOcrResult> ExtractTextAsync(string imagePath,
CancellationToken ct = default);
Task<bool> IsAvailableAsync(CancellationToken ct = default);
}
Використовуючи його:
var vision = serviceProvider.GetRequiredService<IVisionService>();
// Generate a caption describing the image
var caption = await vision.CaptionAsync("photo.jpg", detailed: true);
if (caption.Success)
{
// caption.Caption: "A man in a blue suit standing at a podium"
// caption.DurationMs: how long it took
}
// Extract visible text using Florence-2's built-in OCR
var ocrResult = await vision.ExtractTextAsync("screenshot.png");
if (ocrResult.Success)
{
// ocrResult.Text: the visible text Florence-2 detected
}
| Застосований випадок | Тесеракт МSK2IOcrServiceМSK0 |
Флоренція МSK2 (IVisionService) |
|---|---|---|
| Сканування документів МSK0 Найкращий варіант - швидкий МSK2 точний | Гаразд, але надмірна кількість | |
| Фотографії знаків | Досить МSK1 Краще МSK2 розуміє контекст сцени | |
| Скрині кадри МSK0 Хороша | Хороший МSK2 | |
| Написування зображення | МожешM SK1 не робити цього | Найкращий варіант МSK3 |
| Швидка | Гвидкий (~100msM SK2 МSK3 Повільніший МSK4s) ≥ | |
| Розмір моделі МSK0 ~4МБ МSK2 ~450Мб МСК4 |
Справа в тому, ефективність: використовувати Tesseract для видобутку документів та текстів (itM SK2s МSK3x швидше з МSK4x меншою модельюMSC5 використовувати Флоренцію-2, коли вам дійсно потрібно зображення розуміння.
Флоренція-2 автоM SK1 завантажує свої моделі MSC2MB) на перший раз, щоб {ModelDirectory}/florence2/.
Якщо ви зацікавлені у тому, що відбувається між текстом " в МSK2 та МSK3 entités out NerService робить це в трьох кроках:
БЕРТ не читає слів символи. За замовчанням BertNerTokenizer розділяє ваш текст на частини слів, які BERT розуміє.
// From BertNerTokenizer.cs
// "John Smith works at Microsoft" becomes tokens like:
// [CLS] John Smith works at Micro ##soft [SEP] [PAD] [PAD] ...
//
// Each token tracks its source offset:
// "John" → chars 0-4
// "Smith" → chars 5-10
// "Micro" → chars 20-29 (WordPiece splits "Microsoft")
// "##soft" → chars 20-29 (same source range as "Micro")
І ## префікс WordPiece нотація, що означає "продовжування попереднього слова ". Це те, як BERT обробляє слова, які він не бачив до цього МSK2 не бачила до цього
Токенізований вхід проходить через модель BERT як три тягачі. Від NerService.RunInference():
// From NerService.cs
var inputIdsTensor = new DenseTensor<long>(tokenized.InputIds, [1, seqLen]);
var attentionMaskTensor = new DenseTensor<long>(tokenized.AttentionMask, [1, seqLen]);
var tokenTypeIdsTensor = new DenseTensor<long>(tokenized.TokenTypeIds, [1, seqLen]);
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("input_ids", inputIdsTensor),
NamedOnnxValue.CreateFromTensor("attention_mask", attentionMaskTensor),
NamedOnnxValue.CreateFromTensor("token_type_ids", tokenTypeIdsTensor)
};
using var results = _session!.Run(inputs);
// Output: logits with shape [1, seqLen, 9] — one of 9 labels per token
Виходи моделі Логіти (raw scores) for 9 possible labels per tokenM SK3
Наклейки 9 відповідають Система BIO - стандартне кодування NER, де B МSK1 Починаючий МSK2 Я = Внутрішній
// From NerService.cs
private static readonly string[] DefaultLabels =
["O", "B-MISC", "I-MISC", "B-PER", "I-PER", "B-ORG", "I-ORG", "B-LOC", "I-LOC"];
Ось як зашифровуються речення.
Token: John Smith works at Microsoft in Seattle
Label: B-PER I-PER O O B-ORG O B-LOC
Meaning: Start Continue Not Not Start Not Start
Person Person entity entity Org entity Location
B-PER запускає новий учасник. I-PER продовжується це. Таким чином "John" M SK3 "SmithMSC5 об 'єднуються в один організаційний орган DecodeEntities() метод обробляє це поєднання, включно з фильтрацією довіриM SK1
// From NerService.cs - entity creation with confidence threshold
private void FlushEntity(
List<NerEntity> entities, string text,
string type, int start, int end, float confidence)
{
if (confidence < _config.MinConfidence) return; // Filter low-confidence
var entityText = text[start..end].Trim();
if (string.IsNullOrWhiteSpace(entityText)) return;
entities.Add(new NerEntity
{
Text = entityText,
Label = type,
Confidence = confidence,
StartOffset = start,
EndOffset = end
});
}
Всі моделі завантажуються автоматично після першого використання. Не потрібна ручна інсталяціяM SK1
flowchart TD
CALL["First API call"]
CHECK{"Files exist<br>in cache?"}
YES[Use cached model]
NO["Download to .tmp file"]
MOVE["Atomic rename<br>.tmp → final"]
CALL --> CHECK
CHECK -->|Yes| YES
CHECK -->|No| NO
NO --> MOVE
MOVE --> YES
style NO stroke:#f60,stroke-width:3px
style MOVE stroke:#090,stroke-width:3px
І ModelDownloader завантаження з HuggingFace (NER modelM SK1 і GitHub (tessdata). Він використовує атомну .tmp шаблон - якщо завантаження перервано , жодних пошкоджених файлів не залишилося позадуM SK2
// From ModelDownloader.cs - atomic download pattern
await using var fileStream = new FileStream(tempPath, FileMode.Create,
FileAccess.Write, FileShare.None, 81920, true);
// ... stream download to .tmp file ...
await fileStream.FlushAsync(ct);
fileStream.Close();
File.Move(tempPath, localPath, overwrite: true); // Atomic rename
Початкова точністьキャッシュу: {AppBaseDir}/models/ocrner/
models/ocrner/
ner/
model.onnx (~430MB - BERT NER)
vocab.txt (~230KB - WordPiece vocabulary)
config.json (~1KB - label mapping)
tessdata/
eng.traineddata (~4MB - English OCR data)
florence2/
... (~450MB - Vision model files)
Усе - це одинтон з ліницькою іініціалізацією. дорогі ресурси M SK1ONNX InferenceSession, TesseractEngine, Флоренція -2 модель МSK2 створені один раз при першій використанні і перероблені на весь термін використання
flowchart TD
DI["AddOcrNer()"]
DI --> MD["ModelDownloader<br>(singleton)"]
DI --> PP["ImagePreprocessor<br>(singleton)"]
DI --> NER["NerService<br>(singleton)"]
DI --> OCR["OcrService<br>(singleton)"]
DI --> PIPE["OcrNerPipeline<br>(singleton)"]
DI --> VIS["VisionService<br>(singleton)"]
MD --> NER
MD --> OCR
PP --> OCR
NER --> PIPE
OCR --> PIPE
style DI stroke:#090,stroke-width:3px
Безпека ниток: всі послуги SemaphoreSlim для інициалізації. Багато потоків, які запускають службу одночасно при першій користуванні, спричиняють лише один завантаження /завантаження МSK2
// From NerService.cs - lazy init pattern used by all services
private async Task EnsureInitializedAsync(CancellationToken ct)
{
if (_initialized) return; // Fast path: already loaded
await _initLock.WaitAsync(ct); // Only one thread enters
try
{
if (_initialized) return; // Double-check after lock
var paths = await _downloader.EnsureNerModelAsync(ct);
_tokenizer = new BertNerTokenizer(paths.VocabPath, _config.MaxSequenceLength);
_session = new InferenceSession(paths.ModelPath, sessionOptions);
_initialized = true;
}
finally { _initLock.Release(); }
}
Репо включає в себе Command-line інструмент, збудований з Спектр.Консоль. Це МSK1 спроектовано як МSK2 вершина успіху " \ \ - просто передайте ваші дані і це працює \
cd Mostlylucid.OcrNer.CLI
# NER from text (auto-detected)
dotnet run -- "John Smith works at Microsoft in Seattle"
# OCR from an image (auto-detected)
dotnet run -- invoice.png
# Explicit commands
dotnet run -- ner "Marie Curie won the Nobel Prize in Stockholm"
dotnet run -- ocr scan.png
dotnet run -- caption photo.jpg
Розумне маршрутизування: автомат CLI - визначає ваші наміри Program.cs:
// From Program.cs - smart routing logic
if (IsImageFile(args2[0]) || IsGlobPattern(args2[0]) || Directory.Exists(args2[0]))
{
args2 = ["ocr", .. args2]; // Image file → ocr command
}
else
{
args2 = ["ner", .. args2]; // Text string → ner command
}
Якщо передати текстову стрічку, вона запускає NER. Якщо передувати файл з зображенням , globM SK3 або каталогі МSK4 він запускає OCR MSC5 NER
| Команда МSK1 Що він робить МSK2 Мотор | Швидкість | ||||
|---|---|---|---|---|---|
ner <text> |
Вирізаємо елементи з тексту | BERT NER МSK2ONNXM SK3 МSK4 | ~50ms | МSK6 | |
ocr <path> |
ОКР МSK1 NER з зображеннях МSK2 Тесеракт + BERT မ်SK4 мSK5м M | ||||
caption <path> |
Напис зображення МSK1 опціональний OCR МSK2 ФлоренціяM SK3 (ONNX) |
Теsseract - це початковий OCR-аналізатор тому що це 's МSK1x швидше і оптимізоване для тексту документу МSK2 Флоренція -2 є для, коли вам потрібно розуміти зображення МСК4 заголовки М СК5 текст сцени M СК6 фото знаків MСК7
Ось реальний результат запуску CLI:
dotnet run -- ner "John Smith works at Microsoft in Seattle, Washington."
Input: John Smith works at Microsoft in Seattle, Washington.
╭──────┬────────────┬────────────┬──────────╮
│ Type │ Entity │ Confidence │ Position │
├──────┼────────────┼────────────┼──────────┤
│ PER │ John Smith │ 100% │ 0-10 │
│ ORG │ Microsoft │ 100% │ 20-29 │
│ LOC │ Seattle │ 100% │ 33-40 │
│ LOC │ Washington │ 100% │ 42-52 │
╰──────┴────────────┴────────────┴──────────╯
dotnet run -- ner "Marie Curie won the Nobel Prize in Stockholm"
╭──────┬─────────────┬────────────┬──────────╮
│ Type │ Entity │ Confidence │ Position │
├──────┼─────────────┼────────────┼──────────┤
│ PER │ Marie Curie │ 100% │ 0-11 │
│ MISC │ Nobel Prize │ 100% │ 20-31 │
│ LOC │ Stockholm │ 100% │ 35-44 │
╰──────┴─────────────┴────────────┴──────────╯
Заspeicherти до JSON для програмного використання:
dotnet run -- ner "John Smith works at Microsoft in Seattle, Washington." -o results.json
{
"sourceText": "John Smith works at Microsoft in Seattle, Washington.",
"entityCount": 4,
"entities": [
{
"type": "PER",
"text": "John Smith",
"confidence": 0.9996,
"startOffset": 0,
"endOffset": 10
},
{
"type": "ORG",
"text": "Microsoft",
"confidence": 0.9988,
"startOffset": 20,
"endOffset": 29
},
{
"type": "LOC",
"text": "Seattle",
"confidence": 0.9991,
"startOffset": 33,
"endOffset": 40
},
{
"type": "LOC",
"text": "Washington",
"confidence": 0.9988,
"startOffset": 42,
"endOffset": 52
}
]
}
Обробляйте багатооб 'ємні зображення за допомогою шаблонів чи каталогів
# All PNGs in a directory
dotnet run -- ocr "scans/*.png" -o results.json
# All images in a folder
dotnet run -- ocr ./documents/
# Batch captioning with Florence-2
dotnet run -- caption "photos/*.jpg" --ocr -o captions.md
| Флаг МSK1 Застосовується до МSK2 Описание | ||
|---|---|---|
-c |
ner, ocr |
Minimalний початковий рівень впевненості компанії |
--language |
ocr |
мова Tesseract ( наприклад eng, fra) |
--max-tokens |
ner, ocr |
Максимальна тривалість послідовності BERT |
--model-dir |
ner, ocr, caption |
Запис модельного каталогу пам 'яті |
-p, --preprocess |
ocr, caption |
Установлено для попереднього обробки none, minimal, default, aggressive |
-q, --quiet |
ner, ocr, caption |
Тихий режим МSK1знижений вихід з консолі МSK2 |
-o |
ner, ocr, caption |
вихідний шлях файлу (.txt, .md, .json) |
--ocr |
caption |
Далі запустите OCR під час команди з заголовком |
--ner |
caption |
Вирізає NER з тексту OCR ( упрощує --ocr) |
На даний момент модель NER має повну protectai/bert-base-NER-onnx (~430MBM SK1 Для багатьох випадків використання - особливо на ресурсі МSK3 при обмежених машинах або при обробці великих об 'ємів кількісно (INTM SK1 версія тієї ж моделі була б значно швидша з мінімальним втратою точності
Runtime ONNX підтримує INT8 квантування з-за коробки ,, що зазвичай зменшує розмір моделі на M SK2x і покращує швидкість виведення на \2-3x на процесорі. Це на карті NerModelRepo опція конфігурації вже підтримує вказування на іншу HuggingFace репо, тому, коли ви опублікуєте кількісну модель, ви'd просто змінитеM SK2
{
"OcrNer": {
"NerModelRepo": "protectai/bert-base-NER-onnx-quantized"
}
}
Архітектура розроблена для цього. - замінити модель.
Цей пакет - одноступенча труба: один OCR двигун , один NER-модель МSK2 один опціональний візуальний модель
Для більш складних сценаріїв - читайте текст з будь-що ( рукописні нотатки , фотографії білих таблиць МSK2 низький M SK3 високоякісні камерні знімки ), з мультиплікатором МSK5 консенсус OCR двигуна LucidRAG. Те, що ' це місце, де проживає виробництво МSK2 сорта МСК3 багаторазовий М СК4 фазова версія цієї роботи MСК5
Флоренція-2 є теперішньою межою для локального бачення в цьому пакетіM SK1 Наступним логічним кроком є мультимодальний LLM - модель, яка може бачити зображення і про причину цього в природному мові. Замість відокремленого OCR MSC1 NER крокиM SK2 ви' надсилаєте зображення безпосередньо і запитуєте про структурне виділення
Ось як би API виглядало:
// Hypothetical future IMultimodalService
public interface IMultimodalService
{
Task<StructuredExtractionResult> ExtractAsync(
string imagePath,
string prompt = "Extract all people, organizations, and locations from this image. Return as JSON.",
CancellationToken ct = default);
}
// Usage
var multimodal = serviceProvider.GetRequiredService<IMultimodalService>();
var result = await multimodal.ExtractAsync("business-card.jpg");
// result.Entities: [{ "John Smith", PER }, { "Acme Corp", ORG }, { "New York", LOC }]
// result.RawText: "John Smith, VP Engineering, Acme Corp, New York, NY 10001"
// result.Summary: "Business card for John Smith at Acme Corp in New York"
Малі локальні мультиmodaльні моделі (подібні Phi-3.5-vision або ЛЛАВА) стають достатньо добрими для цього . Торгівля МSK2off завжди одна й та сама МSK3 більша модель Хіба = розумніша, але повільніша \ . Правильний вибір залежить від вашого бюджету на затримку і вимог до точності
flowchart LR
subgraph Staged["Staged Approach: Pick Your Level"]
T1["Tesseract OCR<br>4MB | ~100ms<br>Text extraction"]
T2["BERT NER<br>430MB | ~50ms<br>Entity extraction"]
T3["Florence-2<br>450MB | ~1-3s<br>Image understanding"]
T4["Multimodal LLM<br>2-8GB | ~5-30s<br>Full reasoning"]
end
T1 --> T2
T2 --> T3
T3 -.->|"future"| T4
style T1 stroke:#090,stroke-width:2px
style T2 stroke:#090,stroke-width:2px
style T3 stroke:#f60,stroke-width:2px
style T4 stroke:#999,stroke-width:2px,stroke-dasharray: 5 5
Кожна шкала додає можливостей за рахунок вартості розміру та затримки. У даний момент пакет охоплює тривиміри M SK1 шкало МSK2 це місце, де мультиmodaльні LLM приходять в МSK3 і де LucidRAG це заголовок.
Цей пакет:
Частина 1:
Відлежність:
Подібні статті:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.