Implement IOcrClient
This commit is contained in:
parent
3800c96116
commit
f8c62c6def
@ -2,4 +2,27 @@ namespace OcrClient.Models;
|
||||
|
||||
public class OcrResponse
|
||||
{
|
||||
}
|
||||
public Result? Result { get; set; }
|
||||
}
|
||||
public class Result
|
||||
{
|
||||
public TextAnnotation? TextAnnotation { get; set; }
|
||||
}
|
||||
public class TextAnnotation
|
||||
{
|
||||
public List<Table>? Tables { get; set; }
|
||||
}
|
||||
|
||||
public class Table
|
||||
{
|
||||
public string? RowCount { get; set; }
|
||||
public string? ColumnCount { get; set; }
|
||||
public List<Cell>? Cells { get; set; }
|
||||
}
|
||||
|
||||
public class Cell
|
||||
{
|
||||
public string? RowIndex { get; set; }
|
||||
public string? ColumnIndex { get; set; }
|
||||
public string? Text { get; set; }
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -4,5 +4,5 @@ namespace OcrClient.Services;
|
||||
|
||||
public interface IOcrClient
|
||||
{
|
||||
public Task<OcrResponse> ProcessImage(string base64Image);
|
||||
public Task<IEnumerable<object[,]>> ProcessImage(string base64Image, string xFolderId, string apiKey);
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
using OcrClient.Models;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace OcrClient.Services;
|
||||
|
||||
public class YandexOcrClient : IOcrClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public YandexOcrClient(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public Task<OcrResponse> ProcessImage(string base64Image)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
70
OcrClient/Services/YandexOcrClient.cs
Normal file
70
OcrClient/Services/YandexOcrClient.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using OcrClient.Models;
|
||||
|
||||
namespace OcrClient.Services;
|
||||
|
||||
public class YandexOcrClient : IOcrClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
public YandexOcrClient(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_httpClient.BaseAddress = new Uri("https://ocr.api.cloud.yandex.net/ocr/v1/");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<object[,]>> ProcessImage(string base64Image, string xFolderId, string apiKey)
|
||||
{
|
||||
using StringContent jsonContent = new(
|
||||
JsonConvert.SerializeObject(new
|
||||
{
|
||||
mimeType = "PNG",
|
||||
languageCodes = new string[] { "ru", "en" },
|
||||
model = "table",
|
||||
content = base64Image
|
||||
}),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Api-Key", apiKey);
|
||||
_httpClient.DefaultRequestHeaders.Add("x-folder-id", xFolderId);
|
||||
_httpClient.DefaultRequestHeaders.Add("x-data-logging-enable", "true");
|
||||
|
||||
using HttpResponseMessage response = await _httpClient.PostAsync("recognizeText", jsonContent);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
OcrResponse? deserialized = JsonConvert.DeserializeObject<OcrResponse>(jsonResponse);
|
||||
|
||||
if (deserialized != null)
|
||||
{
|
||||
var tables = deserialized?.Result?.TextAnnotation?.Tables ?? Enumerable.Empty<Table>();
|
||||
if (tables.Any())
|
||||
{
|
||||
List<object[,]> result = new();
|
||||
foreach (var table in tables)
|
||||
{
|
||||
if (table.Cells == null || table.Cells.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int columnCount = int.Parse(table.ColumnCount);
|
||||
int rowCount = int.Parse(table.RowCount);
|
||||
object[,] cells = new object[rowCount, columnCount];
|
||||
|
||||
foreach (Cell cell in table.Cells)
|
||||
{
|
||||
int rowIndex = int.Parse(cell.RowIndex);
|
||||
int columnIndex = int.Parse(cell.ColumnIndex);
|
||||
cells[rowIndex, columnIndex] = double.TryParse(cell.Text, out double v) ?
|
||||
v : cell.Text ?? string.Empty;
|
||||
}
|
||||
result.Add(cells);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ public class RibbonController : ExcelRibbon
|
||||
<button id='dxfexport' getEnabled='GetDxfEnabled' label='DXF' size='large' image='DXF' onAction='OnToolPressed'/>
|
||||
</group>
|
||||
<group id='importTab' label='OCR'>
|
||||
<button id='ocr' label='Распознать таблицу' size='large' imageMso='TableInsert' onAction='OnToolPressed'/>
|
||||
<button id='ocr' getEnabled='GetOcrEnabled' label='Распознать таблицу' size='large' imageMso='TableInsert' onAction='OnToolPressed'/>
|
||||
</group>
|
||||
<group id='settings' getLabel='GetVersionLabel'>
|
||||
<button id='setPriceList' getLabel='GetPriceListPathLabel' size='large' image='RhSolutions' onAction='OnSetPricePressed'/>
|
||||
@ -102,6 +102,13 @@ public class RibbonController : ExcelRibbon
|
||||
return selection.Columns.Count == 2;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetOcrEnabled(IRibbonControl control)
|
||||
{
|
||||
return RhSolutionsAddIn.Excel.ActiveWorkbook != null &&
|
||||
!string.IsNullOrEmpty(RhSolutionsAddIn.Configuration["x-folder-id"]) &&
|
||||
!string.IsNullOrEmpty(RhSolutionsAddIn.Configuration["apiKey"]);
|
||||
}
|
||||
|
||||
public string GetVersionLabel(IRibbonControl control)
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Configuration.UserSecrets;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
@ -33,3 +34,4 @@ using System.Runtime.InteropServices;
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.9.5.1")]
|
||||
[assembly: AssemblyFileVersion("1.9.5.1")]
|
||||
[assembly: UserSecretsId("d4bb704e-14a5-421f-8f2d-0ffb66d090a2")]
|
||||
|
@ -2,12 +2,11 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6.0-windows</TargetFrameworks>
|
||||
<LangVersion>10</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>RhSolutions</RootNamespace>
|
||||
<AssemblyName>RhSolutions.AddIn</AssemblyName>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
<UserSecretsId>d4bb704e-14a5-421f-8f2d-0ffb66d090a2</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<NoWarn>CA1416</NoWarn>
|
||||
@ -21,6 +20,9 @@
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||
<PackageReference Include="netDxf" Version="2022.11.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
@ -28,9 +30,9 @@
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RhSolutions.ProductSku\RhSolutions.ProductSku.csproj" />
|
||||
<ProjectReference Include="..\SnippingTool\SnippingTool.csproj" />
|
||||
<ProjectReference Include="..\OcrClient\OcrClient.csproj" />
|
||||
<ProjectReference Include="..\RhSolutions.ProductSku\RhSolutions.ProductSku.csproj" />
|
||||
<ProjectReference Include="..\SnippingTool\SnippingTool.csproj" />
|
||||
<ProjectReference Include="..\OcrClient\OcrClient.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Images\Coupling.png">
|
||||
|
@ -1,43 +1,58 @@
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Win32;
|
||||
using System.IO;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public class AddInConfiguration : IAddInConfiguration
|
||||
{
|
||||
private RegistryKey _rootKey;
|
||||
private string _priceListPath;
|
||||
private Dictionary<string, string> _priceListHeaders;
|
||||
private IConfiguration _configuration;
|
||||
private RegistryKey _rootKey;
|
||||
private string _priceListPath;
|
||||
private Dictionary<string, string> settingsValues;
|
||||
|
||||
public event IAddInConfiguration.SettingsHandler OnSettingsChange;
|
||||
public string this[string key]
|
||||
{
|
||||
get => _configuration[key];
|
||||
}
|
||||
|
||||
public AddInConfiguration()
|
||||
{
|
||||
_rootKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\RhSolutions\RhSolutions-AddIn");
|
||||
_priceListPath = (string)_rootKey.GetValue("PriceListPath");
|
||||
_priceListHeaders = new()
|
||||
{
|
||||
["Amount"] = "Кол-во",
|
||||
["OldSku"] = "Прежний материал",
|
||||
["Sku"] = "Актуальный материал",
|
||||
["ProductLine"] = "Программа",
|
||||
["Name"] = "Наименование",
|
||||
["Measure"] = "Ед. изм."
|
||||
};
|
||||
}
|
||||
public event IAddInConfiguration.SettingsHandler OnSettingsChange;
|
||||
|
||||
public string GetPriceListFileName() => Path.GetFileName(_priceListPath);
|
||||
public Dictionary<string, string> GetPriceListHeaders() => _priceListHeaders;
|
||||
public string GetPriceListPath() => _priceListPath;
|
||||
public AddInConfiguration()
|
||||
{
|
||||
// EmbeddedFileProvider embeddedProvider = new (typeof(RhSolutionsAddIn).Assembly);
|
||||
// using Stream stream = embeddedProvider.GetFileInfo("appsettings.json").CreateReadStream();
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
_rootKey.SetValue("PriceListPath", _priceListPath);
|
||||
OnSettingsChange.Invoke();
|
||||
}
|
||||
_configuration = new ConfigurationBuilder()
|
||||
.AddUserSecrets<RhSolutionsAddIn>()
|
||||
// .AddJsonStream(stream)
|
||||
.Build();
|
||||
|
||||
public void SetPriceListPath(string value)
|
||||
{
|
||||
_priceListPath = value;
|
||||
}
|
||||
_rootKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\RhSolutions\RhSolutions-AddIn");
|
||||
_priceListPath = (string)_rootKey.GetValue("PriceListPath");
|
||||
settingsValues = new()
|
||||
{
|
||||
["Amount"] = "Кол-во",
|
||||
["OldSku"] = "Прежний материал",
|
||||
["Sku"] = "Актуальный материал",
|
||||
["ProductLine"] = "Программа",
|
||||
["Name"] = "Наименование",
|
||||
["Measure"] = "Ед. изм."
|
||||
};
|
||||
}
|
||||
|
||||
public string GetPriceListFileName() => Path.GetFileName(_priceListPath);
|
||||
public Dictionary<string, string> GetPriceListHeaders() => settingsValues;
|
||||
public string GetPriceListPath() => _priceListPath;
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
_rootKey.SetValue("PriceListPath", _priceListPath);
|
||||
OnSettingsChange.Invoke();
|
||||
}
|
||||
|
||||
public void SetPriceListPath(string value)
|
||||
{
|
||||
_priceListPath = value;
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
namespace RhSolutions.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace RhSolutions.Services;
|
||||
|
||||
public interface IAddInConfiguration
|
||||
{
|
||||
public string GetPriceListPath();
|
||||
public void SetPriceListPath(string value);
|
||||
public string GetPriceListFileName();
|
||||
public Dictionary<string, string> GetPriceListHeaders();
|
||||
public delegate void SettingsHandler();
|
||||
public event SettingsHandler OnSettingsChange;
|
||||
public void SaveSettings();
|
||||
string this[string key] { get; }
|
||||
public string GetPriceListPath();
|
||||
public void SetPriceListPath(string value);
|
||||
public string GetPriceListFileName();
|
||||
public Dictionary<string, string> GetPriceListHeaders();
|
||||
public delegate void SettingsHandler();
|
||||
public event SettingsHandler OnSettingsChange;
|
||||
public void SaveSettings();
|
||||
}
|
@ -4,40 +4,41 @@ namespace RhSolutions.Tools;
|
||||
|
||||
internal static class EventsUtil
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
RibbonController.EnsurePriseListExists();
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange += RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange += RefreshSettingTitle;
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
RibbonController.EnsurePriseListExists();
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange += RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate += RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange += RefreshSettingTitle;
|
||||
}
|
||||
|
||||
public static void Uninitialize()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange -= RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange -= RefreshSettingTitle;
|
||||
}
|
||||
public static void Uninitialize()
|
||||
{
|
||||
RhSolutionsAddIn.Excel.SheetSelectionChange -= RefreshExportButton;
|
||||
RhSolutionsAddIn.Excel.SheetActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Excel.WorkbookActivate -= RefreshButtons;
|
||||
RhSolutionsAddIn.Configuration.OnSettingsChange -= RefreshSettingTitle;
|
||||
}
|
||||
|
||||
private static void RefreshButtons(object sh)
|
||||
{
|
||||
RibbonController.UpdateWorkbookValidation();
|
||||
RibbonController.RefreshControl("convert");
|
||||
RibbonController.RefreshControl("dxfexport");
|
||||
RibbonController.RefreshControl("guess");
|
||||
RibbonController.RefreshControl("fillsleeves");
|
||||
RibbonController.RefreshControl("fillcouplings");
|
||||
}
|
||||
private static void RefreshButtons(object sh)
|
||||
{
|
||||
RibbonController.UpdateWorkbookValidation();
|
||||
RibbonController.RefreshControl("convert");
|
||||
RibbonController.RefreshControl("dxfexport");
|
||||
RibbonController.RefreshControl("guess");
|
||||
RibbonController.RefreshControl("fillsleeves");
|
||||
RibbonController.RefreshControl("fillcouplings");
|
||||
RibbonController.RefreshControl("ocr");
|
||||
}
|
||||
|
||||
private static void RefreshExportButton(object sh, Range target)
|
||||
{
|
||||
RibbonController.RefreshControl("export");
|
||||
}
|
||||
private static void RefreshExportButton(object sh, Range target)
|
||||
{
|
||||
RibbonController.RefreshControl("export");
|
||||
}
|
||||
|
||||
private static void RefreshSettingTitle()
|
||||
{
|
||||
RibbonController.RefreshControl("setPriceList");
|
||||
}
|
||||
private static void RefreshSettingTitle()
|
||||
{
|
||||
RibbonController.RefreshControl("setPriceList");
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,19 @@
|
||||
using System.Threading.Tasks;
|
||||
using SnippingTool;
|
||||
using OcrClient.Services;
|
||||
using System.Windows.Forms;
|
||||
using Application = Microsoft.Office.Interop.Excel.Application;
|
||||
|
||||
namespace RhSolutions.Tools;
|
||||
|
||||
internal class OcrTool : ITool
|
||||
{
|
||||
private IOcrClient client = RhSolutionsAddIn.ServiceProvider.GetService<IOcrClient>();
|
||||
private Application app = RhSolutionsAddIn.Excel;
|
||||
private string xFolderId = RhSolutionsAddIn.Configuration["x-folder-id"];
|
||||
private string apiKey = RhSolutionsAddIn.Configuration["apiKey"];
|
||||
|
||||
public void Execute()
|
||||
public async void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -19,7 +24,46 @@ internal class OcrTool : ITool
|
||||
}).Wait();
|
||||
|
||||
string shot = Snipper.SnipBase64();
|
||||
var result = client.ProcessImage(shot);
|
||||
RhSolutionsAddIn.Excel.Visible = true;
|
||||
|
||||
if (shot != null)
|
||||
{
|
||||
IEnumerable<object[,]> tables = await client.ProcessImage(shot, xFolderId, apiKey);
|
||||
if (tables != null)
|
||||
{
|
||||
foreach (var table in tables)
|
||||
{
|
||||
int rowCount = table.GetLength(0);
|
||||
int columnCount = table.GetLength(1);
|
||||
|
||||
Range currentCell = app.ActiveCell;
|
||||
Range tableRange = app.ActiveSheet.Range(currentCell,
|
||||
app.ActiveSheet.Cells(currentCell.Row + rowCount - 1, currentCell.Column + columnCount - 1));
|
||||
|
||||
if (app.WorksheetFunction.CountA(tableRange) > 0)
|
||||
{
|
||||
MessageBox.Show(@"На листе отсустствует диапазон для вставки распознанной таблицы.Попробуйте в другом месте или на пустом листе.",
|
||||
"Ошибка",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
RhSolutionsAddIn.Excel.Visible = true;
|
||||
return;
|
||||
}
|
||||
tableRange.Borders.LineStyle = XlLineStyle.xlContinuous;
|
||||
|
||||
for (int row = 0; row < rowCount; row++)
|
||||
for (int column = 0; column < columnCount; column++)
|
||||
{
|
||||
Range excelCell = app.ActiveSheet.Cells(currentCell.Row + row,
|
||||
currentCell.Column + column);
|
||||
excelCell.Value2 = table[row,column];
|
||||
excelCell.EntireColumn.AutoFit();
|
||||
excelCell.EntireRow.AutoFit();
|
||||
}
|
||||
app.ActiveSheet.Cells(currentCell.Row + rowCount + 1, currentCell.Column).Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user