📑 فهرست مطالب
- تحلیل وضعیت فعلی و شکافها
- استراتژی معماری جدید
- گام ۱: بازطراحی Interface با خروجی چندگانه
- گام ۲: پیادهسازی ImageContentExtractor
- گام ۳: پیادهسازی AudioContentExtractor
- گام ۴: ارتقای PdfExtractor با Fallback تصویری
- گام ۵: یکپارچهسازی در XAIServiceBase
- گام ۶: ثبت در DI و پیکربندی
- جریان کامل پردازش
- خلاصه تغییرات و پکیجها
🔍 گام ۱: تحلیل وضعیت فعلی و شکافها
۱.۱ وضعیت فعلی Extractor ها:
| Extractor | وضعیت | نوع خروجی | شکاف |
|---|---|---|---|
XPlainTextFileContentExtractor |
✅ موجود | Text | - |
XDocxFileContentExtractor |
✅ موجود | Text | عدم پشتیبانی از تصاویر داخل DOCX |
XExcelFileContentExtractor |
✅ موجود | Text (Tabular) | - |
XPdfFileContentExtractor |
⚠️ ناقص | Text | عدم Fallback برای PDF های اسکنشده |
| Image Extractor | ❌ موجود نیست | - | نیاز به پیادهسازی (Vision API) |
| Audio Extractor | ❌ موجود نیست | - | نیاز به پیادهسازی (Whisper) |
۱.۲ مشکل اساسی در IXFileContentExtractor فعلی:
Interface فعلی فقط یک string برمیگرداند. این برای متن کافی است اما برای تصویر و صوت نیاز به ساختار دادهای غنیتر داریم که بتواند چندین نوع محتوا (Text + Images + Audio) را همزمان حمل کند.
// ❌ Interface فعلی - محدود به string
public interface IXFileContentExtractor
{
bool CanExtract(string mimeType);
Task<string> ExtractAsync(Stream fileStream, string mimeType, ...);
}
🎯 گام ۲: استراتژی معماری جدید
📦 خروجی چندگانه (Multi-Content)
- ایجاد
XFileExtractionResult - شامل: Text, Images[], AudioTranscript
- سازگار با
AIContent
🖼️ پشتیبانی تصویر (Vision)
- ارسال به عنوان
DataContent - سازگار با Gemini, GPT-4V, Qwen-VL
- OCR محلی به عنوان Fallback
🎙️ پشتیبانی صوت (Whisper)
- تبدیل Speech-to-Text
- استفاده از Whisper محلی یا API
- خروجی به صورت متن
📄 PDF Fallback هوشمند
- استخراج متن ابتدا
- اگر متن خالی/کمحجم → تبدیل به تصویر
- ارسال صفحات به عنوان Vision
ExtractAsync استفاده میکنند، بدون تغییر کار خواهند کرد.
🔧 گام ۳: بازطراحی Interface با خروجی چندگانه
using System;
using System.Collections.Generic;
using System.Linq;
using xCommons.Extensions;
using Microsoft.Extensions.AI;
namespace xAiApi.Models
{
/// <summary>
/// نتیجه استخراج محتوا از فایل - میتواند شامل متن، تصاویر و صوت باشد ...
/// </summary>
public class XFileExtractionResult
{
/// <summary>
/// محتوای متنی استخراج شده ...
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// تصاویر استخراج شده (برای Vision Models) ...
/// </summary>
public IList<XExtractedImage> Images { get; set; } = [];
/// <summary>
/// متن تبدیل شده از صوت ...
/// </summary>
public string AudioTranscript { get; set; } = string.Empty;
/// <summary>
/// نام فایل اصلی ...
/// </summary>
public string FileName { get; set; }
/// <summary>
/// MIME Type فایل ...
/// </summary>
public string MimeType { get; set; }
/// <summary>
/// آیا استخراج با Fallback تصویری انجام شده است ...
/// </summary>
public bool UsedImageFallback { get; set; } = false;
/// <summary>
/// پیام خطا (در صورت بروز مشکل) ...
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// آیا نتیجه معتبر است ...
/// </summary>
public bool IsValid()
{
return !Text.IsNullOrEmpty() ||
Images.HasChild() ||
!AudioTranscript.IsNullOrEmpty();
}
/// <summary>
/// تبدیل به لیست AIContent برای ارسال به LLM ...
/// </summary>
public IList<AIContent> ToAIContents()
{
var result = new List<AIContent>();
// ۱. افزودن متن اصلی
if (!Text.IsNullOrEmpty())
{
result.Add(new TextContent(Text));
}
// ۲. افزودن تصاویر (برای Vision Models)
if (Images.HasChild())
{
foreach (var img in Images)
{
result.Add(new DataContent(img.Bytes, img.MimeType));
}
}
// ۳. افزودن transcript صوت
if (!AudioTranscript.IsNullOrEmpty())
{
result.Add(new TextContent($"[Audio Transcript]\n{AudioTranscript}"));
}
return result;
}
}
/// <summary>
/// تصویر استخراج شده از فایل ...
/// </summary>
public class XExtractedImage
{
/// <summary>
/// داده بایت تصویر ...
/// </summary>
public byte[] Bytes { get; set; }
/// <summary>
/// MIME Type تصویر ...
/// </summary>
public string MimeType { get; set; } = "image/png";
/// <summary>
/// شماره صفحه (برای PDF) ...
/// </summary>
public int? PageNumber { get; set; }
/// <summary>
/// توضیح تصویر ...
/// </summary>
public string Description { get; set; }
}
}
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using xAiApi.Models;
namespace xAiApi.Interfaces.Extractors
{
/// <summary>
/// سرویس استخراج محتوای فایل - نسخه ارتقا یافته با پشتیبانی چندوجهی ...
/// </summary>
public interface IXFileContentExtractor
{
/// <summary>
/// بررسی پشتیبانی از MIME Type مشخص ...
/// </summary>
bool CanExtract(string mimeType);
/// <summary>
/// استخراج محتوای فایل با خروجی غنی (متن + تصویر + صوت) ...
/// </summary>
Task<XFileExtractionResult> ExtractRichAsync(
Stream fileStream,
string fileName,
string mimeType,
CancellationToken cancellationToken = default
);
/// <summary>
/// استخراج محتوای متنی (سازگار با نسخه قبل) ...
/// </summary>
Task<string> ExtractAsync(
Stream fileStream,
string mimeType,
CancellationToken cancellationToken = default
);
}
}
🖼️ گام ۴: پیادهسازی ImageContentExtractor
این Extractor تصاویر را برای مدلهای Vision آماده میکند. دو حالت پشتیبانی میشود:
- حالت ۱ (Vision API): ارسال مستقیم به عنوان
DataContentبه مدلهای چندوجهی - حالت ۲ (OCR Fallback): استخراج متن با Tesseract برای مدلهای متنی
namespace xAiApi.Interfaces.Extractors
{
/// <summary>
/// Extractor اختصاصی برای فایلهای تصویری ...
/// </summary>
public interface IXImageFileContentExtractor : IXFileContentExtractor
{ }
}
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using xAiApi.Models;
using xAiApi.Interfaces.Extractors;
namespace xAiApi.Providers.Extractors
{
/// <summary>
/// استخراج محتوا از فایلهای تصویری - پشتیبانی از Vision و OCR ...
/// </summary>
public class XImageFileContentExtractor : IXImageFileContentExtractor
{
private static readonly string[] SupportedMimeTypes =
[
"image/png",
"image/jpeg",
"image/jpg",
"image/gif",
"image/webp",
"image/bmp"
];
/// <summary>
/// آیا OCR فعال است (برای مدلهای غیر Vision) ...
/// </summary>
private readonly bool _enableOcrFallback;
public XImageFileContentExtractor(bool enableOcrFallback = true)
{
_enableOcrFallback = enableOcrFallback;
}
public bool CanExtract(string mimeType)
{
return SupportedMimeTypes.Contains(
mimeType?.ToLowerInvariant() ?? string.Empty
);
}
public async Task<XFileExtractionResult> ExtractRichAsync(
Stream fileStream,
string fileName,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = new XFileExtractionResult
{
FileName = fileName,
MimeType = mimeType
};
// خواندن بایتهای تصویر
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream, cancellationToken);
var imageBytes = memoryStream.ToArray();
// افزودن به عنوان تصویر برای Vision Models
result.Images.Add(new XExtractedImage
{
Bytes = imageBytes,
MimeType = mimeType,
Description = $"Attached image: {fileName}"
});
// OCR Fallback برای مدلهای متنی
if (_enableOcrFallback)
{
try
{
var ocrText = await PerformOcrAsync(imageBytes, cancellationToken);
if (!string.IsNullOrWhiteSpace(ocrText))
{
result.Text = ocrText;
}
}
catch
{
// OCR failed, but image is still available for Vision
}
}
return result;
}
public async Task<string> ExtractAsync(
Stream fileStream,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = await ExtractRichAsync(
fileStream,
"image",
mimeType,
cancellationToken
);
return result.Text;
}
/// <summary>
/// انجام OCR روی تصویر - با استفاده از Tesseract ...
/// </summary>
private async Task<string> PerformOcrAsync(
byte[] imageBytes,
CancellationToken cancellationToken
)
{
// پیادهسازی با Tesseract یا هر کتابخانه OCR دیگر
// در حال حاضر یک placeholder است
return await Task.FromResult(string.Empty);
}
}
}
Tesseract- کتابخانه قدرتمند و متنبازMicrosoft.Azure.CognitiveServices.Vision.ComputerVision- اگر از Azure استفاده میکنید
🎙️ گام ۵: پیادهسازی AudioContentExtractor
این Extractor فایلهای صوتی را با استفاده از Whisper به متن تبدیل میکند.
namespace xAiApi.Interfaces.Extractors
{
/// <summary>
/// Extractor اختصاصی برای فایلهای صوتی ...
/// </summary>
public interface IXAudioFileContentExtractor : IXFileContentExtractor
{ }
}
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using xAiApi.Models;
using xAiApi.Interfaces.Extractors;
// Install-Package Whisper.net
// Install-Package Whisper.net.Runtime
using Whisper.net;
namespace xAiApi.Providers.Extractors
{
/// <summary>
/// استخراج متن از فایلهای صوتی با استفاده از Whisper ...
/// </summary>
public class XAudioFileContentExtractor : IXAudioFileContentExtractor
{
private static readonly string[] SupportedMimeTypes =
[
"audio/mpeg",
"audio/mp3",
"audio/wav",
"audio/wave",
"audio/ogg",
"audio/m4a",
"audio/mp4",
"audio/webm"
];
private readonly string _whisperModelPath;
private readonly string _language;
public XAudioFileContentExtractor(
string whisperModelPath = "Models/ggml-base.bin",
string language = "fa" // فارسی پیشفرض
)
{
_whisperModelPath = whisperModelPath;
_language = language;
}
public bool CanExtract(string mimeType)
{
return SupportedMimeTypes.Contains(
mimeType?.ToLowerInvariant() ?? string.Empty
);
}
public async Task<XFileExtractionResult> ExtractRichAsync(
Stream fileStream,
string fileName,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = new XFileExtractionResult
{
FileName = fileName,
MimeType = mimeType
};
try
{
// کپی به MemoryStream برای Whisper
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream, cancellationToken);
memoryStream.Position = 0;
// تبدیل به فرمت WAV 16kHz (مورد نیاز Whisper)
using var wavStream = await ConvertToWavAsync(memoryStream, cancellationToken);
// انجام Speech-to-Text با Whisper
using var factory = WhisperFactory.FromPath(_whisperModelPath);
using var processor = factory.CreateBuilder()
.WithLanguage(_language)
.Build();
var segments = new System.Text.StringBuilder();
await foreach (var segment in processor.ProcessAsync(wavStream, cancellationToken))
{
segments.Append(segment.Text);
}
result.AudioTranscript = segments.ToString().Trim();
result.Text = result.AudioTranscript;
}
catch (Exception ex)
{
result.ErrorMessage = $"Audio extraction failed: {ex.Message}";
}
return result;
}
public async Task<string> ExtractAsync(
Stream fileStream,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = await ExtractRichAsync(
fileStream,
"audio",
mimeType,
cancellationToken
);
return result.AudioTranscript;
}
/// <summary>
/// تبدیل فرمت صوتی به WAV 16kHz (فرمت مورد نیاز Whisper) ...
/// </summary>
private async Task<Stream> ConvertToWavAsync(
Stream inputStream,
CancellationToken cancellationToken
)
{
// پیادهسازی با NAudio یا ffmpeg
// در حال حاضر یک placeholder است
return await Task.FromResult(inputStream);
}
}
}
Whisper.net- پیادهسازی C# از WhisperWhisper.net.Runtime- Runtime مورد نیازNAudio- برای تبدیل فرمت صوتی
دانلود مدل Whisper: از HuggingFace مدل ggml-base.bin یا ggml-small.bin را دانلود کنید.
📄 گام ۶: ارتقای PdfExtractor با Fallback تصویری
این مهمترین بخش است. اگر PDF متن نداشت (اسکنشده بود)، صفحات را به تصویر تبدیل میکنیم.
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UglyToad.PdfPig;
using UglyToad.PdfPig.Rendering;
using xAiApi.Models;
using xAiApi.Interfaces.Extractors;
namespace xAiApi.Providers
{
/// <summary>
/// استخراج محتوا از PDF - با Fallback هوشمند برای PDF های اسکنشده ...
/// </summary>
public class XPdfFileContentExtractor : IXPdfFileContentExtractor
{
private static readonly string[] SupportedMimeTypes = ["application/pdf"];
/// <summary>
/// حداقل تعداد کاراکتر برای تشخیص PDF متنی ...
/// </summary>
private const int MinTextLengthThreshold = 50;
/// <summary>
/// حداکثر تعداد صفحات برای تبدیل به تصویر ...
/// </summary>
private const int MaxPagesForImageFallback = 10;
public bool CanExtract(string mimeType)
{
return SupportedMimeTypes.Contains(
mimeType?.ToLowerInvariant() ?? string.Empty
);
}
public async Task<XFileExtractionResult> ExtractRichAsync(
Stream fileStream,
string fileName,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = new XFileExtractionResult
{
FileName = fileName,
MimeType = mimeType
};
// کپی به MemoryStream
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream, cancellationToken);
memoryStream.Position = 0;
// مرحله ۱: تلاش برای استخراج متن
var extractedText = await ExtractTextAsync(memoryStream, cancellationToken);
// مرحله ۲: بررسی کیفیت متن استخراج شده
if (IsTextSufficient(extractedText))
{
// PDF متنی است
result.Text = extractedText;
}
else
{
// PDF اسکنشده است - Fallback به تصویر
memoryStream.Position = 0;
result = await FallbackToImageExtractionAsync(
memoryStream,
fileName,
mimeType,
cancellationToken
);
result.UsedImageFallback = true;
}
return result;
}
public async Task<string> ExtractAsync(
Stream fileStream,
string mimeType,
CancellationToken cancellationToken = default
)
{
var result = await ExtractRichAsync(
fileStream,
"document.pdf",
mimeType,
cancellationToken
);
return result.Text;
}
/// <summary>
/// استخراج متن از PDF ...
/// </summary>
private async Task<string> ExtractTextAsync(
Stream pdfStream,
CancellationToken cancellationToken
)
{
return await Task.Run(() =>
{
var sb = new StringBuilder();
using var document = PdfDocument.Open(pdfStream);
foreach (var page in document.GetPages())
{
var text = page.Text?.Trim();
if (!string.IsNullOrEmpty(text))
{
sb.AppendLine(text);
sb.AppendLine();
}
}
return sb.ToString();
}, cancellationToken);
}
/// <summary>
/// بررسی آیا متن استخراج شده کافی است ...
/// </summary>
private bool IsTextSufficient(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return false;
}
// حذف فاصلهها و بررسی طول
var cleanText = new string(text.Where(c => !char.IsWhiteSpace(c)).ToArray());
return cleanText.Length >= MinTextLengthThreshold;
}
/// <summary>
/// Fallback: تبدیل صفحات PDF به تصویر ...
/// </summary>
private async Task<XFileExtractionResult> FallbackToImageExtractionAsync(
Stream pdfStream,
string fileName,
string mimeType,
CancellationToken cancellationToken
)
{
var result = new XFileExtractionResult
{
FileName = fileName,
MimeType = mimeType,
UsedImageFallback = true
};
await Task.Run(() =>
{
using var document = PdfDocument.Open(pdfStream);
using var renderer = new PdfPigRenderer(document);
var pageCount = Math.Min(
document.NumberOfPages,
MaxPagesForImageFallback
);
for (int i = 0; i < pageCount; i++)
{
var page = document.GetPage(i);
var bitmap = renderer.Render(page);
// تبدیل Bitmap به PNG
using var memoryStream = new MemoryStream();
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
var imageBytes = memoryStream.ToArray();
result.Images.Add(new XExtractedImage
{
Bytes = imageBytes,
MimeType = "image/png",
PageNumber = i + 1,
Description = $"Page {i + 1} of {fileName}"
});
}
}, cancellationToken);
return result;
}
}
}
UglyToad.PdfPig- قبلاً نصب شدهSystem.Drawing.Common- برای کار با Bitmap
نکته: PdfPigRenderer در نسخههای جدید PdfPig وجود دارد. اگر نبود، از Docnet یا PdfiumViewer استفاده کنید.
🔗 گام ۷: یکپارچهسازی در XAIServiceBase
اصلاح متد AskAsync - بخش پردازش فایلها:
// در متد AskAsync، بعد از آپلود فایلها و AddReference:
// ✅ استخراج محتوای فایلها با خروجی غنی
IList<AIContent> fileContents = null;
if (uploadedFiles.HasChild())
{
fileContents = new List<AIContent>();
foreach (var uploadedFile in uploadedFiles)
{
try
{
// دریافت Stream فایل از FileProvider
var fileDescriptor = await fileProvider.GetFileDescriptor(
id: uploadedFile.Id,
cancellationToken: cancellationToken
);
if (fileDescriptor == null || fileDescriptor.Stream == null)
{
continue;
}
// استخراج محتوا با استفاده از Composite Extractor
var extractionResult = await fileContentExtractor.ExtractRichAsync(
fileStream: fileDescriptor.Stream,
fileName: uploadedFile.FileName ?? uploadedFile.Name,
mimeType: fileDescriptor.MIMEType,
cancellationToken: cancellationToken
);
if (extractionResult.IsValid())
{
// تبدیل به AIContent
var contents = extractionResult.ToAIContents();
fileContents.AddRange(contents);
// ذخیره Metadata برای ردیابی
logger.LogInformation(
"File {FileName} extracted successfully. Text: {HasText}, Images: {ImageCount}, Fallback: {UsedFallback}",
uploadedFile.FileName,
!string.IsNullOrEmpty(extractionResult.Text),
extractionResult.Images.Count,
extractionResult.UsedImageFallback
);
}
fileDescriptor.Stream.Dispose();
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to extract content from file: {FileName}", uploadedFile.FileName);
}
}
}
// تبدیل به ChatMessage با محتوای فایلها
var promptChatMessage = promptMessage.ToChatMessages(fileContents);
اصلاح متد ToChatMessages برای پشتیبانی از محتوای چندگانه:
public static ChatMessage ToChatMessages(
this XAiMessageDto source,
IList<AIContent> additionalContents = null
)
{
ChatMessage result = null;
if (!source.IsNullOrDefault())
{
var contents = new List<AIContent>();
// ۱. افزودن متن اصلی پیام
if (!string.IsNullOrWhiteSpace(source.Content))
{
contents.Add(new TextContent(source.Content));
}
// ۲. ✅ افزودن محتوای فایلهای ضمیمه (متن + تصویر + صوت)
if (additionalContents != null && additionalContents.HasChild())
{
contents.AddRange(additionalContents);
}
result = new ChatMessage
{
AuthorName =
source.Role == XAiChatRole.User &&
!source.Owner.IsNullOrDefault()
? source.Owner.GetFullname()
: string.Empty,
Role = source.Role.ToChatRole(),
MessageId = source.Id.ToString(),
Contents = contents
};
}
return result;
}
🔌 گام ۸: ثبت در DI و پیکربندی
public void ConfigureServices(IServiceCollection services)
{
// ... (سایر ثبتها)
// ✅ ثبت Extractor های فایل
services.AddSingleton<IXFileContentExtractor, XPlainTextFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XDocxFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XExcelFileContentExtractor>();
// ✅ Extractor های جدید
services.AddSingleton<IXFileContentExtractor>(sp =>
new XImageFileContentExtractor(enableOcrFallback: true));
services.AddSingleton<IXFileContentExtractor>(sp =>
new XAudioFileContentExtractor(
whisperModelPath: "Models/ggml-base.bin",
language: "fa"
));
services.AddSingleton<IXFileContentExtractor, XPdfFileContentExtractor>();
// ✅ ثبت Composite Extractor
services.AddSingleton<IXFileContentExtractor, XFileContentExtractor>();
// ... (بقیه کدها)
}
appsettings.json:
{
"AiApiConfiguration": {
"FileExtraction": {
"EnableOcrFallback": true,
"WhisperModelPath": "Models/ggml-base.bin",
"WhisperLanguage": "fa",
"MaxPdfPagesForImageFallback": 10,
"MinTextLengthThreshold": 50
}
}
}
🔄 گام ۹: جریان کامل پردازش
مثالهای کاربردی:
| نوع فایل | استراتژی پردازش | خروجی |
|---|---|---|
| 📄 PDF متنی | استخراج متن با PdfPig | Text |
| 📄 PDF اسکنشده | تبدیل صفحات به PNG | Images[] (Vision) |
| 🖼️ تصویر (PNG/JPG) | ارسال مستقیم + OCR | Image + Text (OCR) |
| 🎙️ صوت (MP3/WAV) | Whisper Speech-to-Text | AudioTranscript |
| 📝 Word (DOCX) | استخراج متن با OpenXml | Text |
| 📊 Excel (XLSX) | استخراج جدول با ExcelDataReader | Text (Tabular) |
📋 گام ۱۰: خلاصه تغییرات و پکیجها
فایلهای جدید:
| فایل | توضیح |
|---|---|
xAiApi/Models/XFileExtractionResult.cs |
مدل خروجی غنی با پشتیبانی از Text + Images + Audio |
xAiApi/Interfaces/Extractors/IXImageFileContentExtractor.cs |
Interface برای Image Extractor |
xAiApi/Interfaces/Extractors/IXAudioFileContentExtractor.cs |
Interface برای Audio Extractor |
xAiApi/Providers/Extractors/XImageFileContentExtractor.cs |
پیادهسازی Image Extractor با Vision + OCR |
xAiApi/Providers/Extractors/XAudioFileContentExtractor.cs |
پیادهسازی Audio Extractor با Whisper |
فایلهای اصلاحشده:
| فایل | تغییر |
|---|---|
xAiApi/Interfaces/Extractors/IXFileContentExtractor.cs |
افزودن متد ExtractRichAsync |
xAiApi/Providers/Extractors/XPdfFileContentExtractor.cs |
افزودن Fallback تصویری برای PDF های اسکنشده |
xAiApi/Providers/XAIServiceBase.cs |
استفاده از ExtractRichAsync و پردازش چندوجهی |
xAiModels/Extensions/XAiModelsExtensions.cs |
پشتیبانی از additionalContents در ToChatMessages |
xAiApi/Startup.cs |
ثبت Extractor های جدید در DI |
پکیجهای NuGet مورد نیاز:
| پکیج | کاربرد | وضعیت |
|---|---|---|
UglyToad.PdfPig |
استخراج متن و تصویر از PDF | ✅ نصب شده |
DocumentFormat.OpenXml |
استخراج متن از DOCX | ✅ نصب شده |
ExcelDataReader |
استخراج متن از Excel | ✅ نصب شده |
System.Drawing.Common |
کار با Bitmap برای PDF به تصویر | ❌ نیاز به نصب |
Whisper.net |
Speech-to-Text محلی | ❌ نیاز به نصب |
Whisper.net.Runtime |
Runtime برای Whisper | ❌ نیاز به نصب |
NAudio |
تبدیل فرمت صوتی | ❌ نیاز به نصب |
Tesseract (اختیاری) |
OCR برای تصاویر | ⚠️ اختیاری |
- 🎨 پشتیبانی چندوجهی کامل: متن، تصویر، صوت
- 📄 PDF هوشمند: تشخیص خودکار PDF متنی/اسکنشده
- 🔄 Fallback خودکار: تبدیل به تصویر در صورت عدم وجود متن
- 🎙️ Speech-to-Text محلی: بدون نیاز به API خارجی
- 🖼️ Vision API Ready: سازگار با Gemini, GPT-4V, Qwen-VL
- 🔌 Backward Compatible: کدهای موجود بدون تغییر کار میکنند