mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-29 18:49:08 +08:00
!3771 feat(#I6AY0F): add baidu ocr component
* doc: 更新使用方法 * doc: 增加源码链接配置 * doc: 增加 IBarduOcr 菜单 * chore: 移除重复菜单 * doc: 增加增值税票据识别组件菜单 * Merge branch 'main' into feat/Baidu.Orc * doc: 更新示例 * refactor: 更改 SaveToFile 方法为异步方法 * refactor: SaveToFile 更改为扩展方法 * refactor: GetBytes 更改为扩展方法 * refactor: RequestBase64ImageFileAsync 更改为扩展方法 * doc: 增加格式化 * doc: 增加发票明细列表 * doc: 更新 Tips 文档 * doc: 不显示已上传列表 * chore: 更新项目依赖项 * doc: 格式化文档 * doc: 增加 BaiduOcr 示例 * chore: 增加 Logo * refactor: 更新 UploadFile * doc: 更新示例 * feat: 增加增值税识别方法 * feat: 增加增值税实体类 * doc: 增加反序列化示例 * doc: 增加 BaiduOrc 示例 * feat: 更新 IBaiduOrc 接口 * chore: 增加 BaiduOrc 识别服务 * feat: 增加百度增值税发票识别接口 * chore: 增加百度文字识别配置项 * doc: 增加注释 * Merge branch 'main' into feat/Baidu.Orc * chore: 增加 BaiduOcr 工程 * refactor: 精简代码消除警告信息 * feat: 增加文字识别服务
This commit is contained in:
parent
35726b0a38
commit
293bbf2c23
@ -140,6 +140,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization", "localizatio
|
||||
localization\zh-TW.json = localization\zh-TW.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.BaiduOcr", "src\Extensions\Components\BootstrapBlazor.BaiduOcr\BootstrapBlazor.BaiduOcr.csproj", "{F800DC0F-6829-4B64-B96B-B301A512AF2A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -234,6 +236,10 @@ Global
|
||||
{7F7F3B85-7B15-485C-8DC2-BAFD8C086957}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F7F3B85-7B15-485C-8DC2-BAFD8C086957}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7F7F3B85-7B15-485C-8DC2-BAFD8C086957}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F800DC0F-6829-4B64-B96B-B301A512AF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F800DC0F-6829-4B64-B96B-B301A512AF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F800DC0F-6829-4B64-B96B-B301A512AF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F800DC0F-6829-4B64-B96B-B301A512AF2A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -271,6 +277,7 @@ Global
|
||||
{9552B649-17E2-4BCA-8774-664C83A960CB} = {7C1D79F1-87BC-42C1-BD5A-CDE4044AC1BD}
|
||||
{6312863E-771D-4EFE-9B9D-071A01222E7A} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
|
||||
{7F7F3B85-7B15-485C-8DC2-BAFD8C086957} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
|
||||
{F800DC0F-6829-4B64-B96B-B301A512AF2A} = {CD062AB6-244D-402A-8F33-C37DAC5856CC}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0DCB0756-34FA-4FD0-AE1D-D3F08B5B3A6B}
|
||||
|
@ -55,6 +55,9 @@ internal static class ServicesExtensions
|
||||
// 设置地理位置定位器
|
||||
services.ConfigureIPLocatorOption(op => op.LocatorFactory = sp => new BaiDuIPLocator());
|
||||
|
||||
// 增加 Baidu ORC 服务
|
||||
services.AddBootstrapBlazorBaiduOcr();
|
||||
|
||||
// 增加多语言支持配置信息
|
||||
services.AddRequestLocalization<IOptionsMonitor<BootstrapBlazorOptions>>((localizerOption, blazorOption) =>
|
||||
{
|
||||
|
@ -63,5 +63,10 @@
|
||||
"AppId": "<AppId>",
|
||||
"ApiKey": "<ApiKey>",
|
||||
"Secret": "<Secret>"
|
||||
},
|
||||
"BaiduOcrOption": {
|
||||
"AppId": "<AppId>",
|
||||
"ApiKey": "<ApiKey>",
|
||||
"Secret": "<Secret>"
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,12 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor.BaiduSpeech" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.BaiduOcr" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.BarCode" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.Bluetooth" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.Chart" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.CherryMarkdown" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.FileViewer" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.Markdown" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.OnScreenKeyboard" Version="7.*" />
|
||||
@ -32,7 +34,6 @@
|
||||
<PackageReference Include="BootstrapBlazor.TableExport" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.Topology" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.VideoPlayer" Version="7.*" />
|
||||
<PackageReference Include="BootstrapBlazor.FileViewer" Version="7.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
100
src/BootstrapBlazor.Shared/Demos/BaiduOcr/BaiduOcrNormal.razor
Normal file
100
src/BootstrapBlazor.Shared/Demos/BaiduOcr/BaiduOcrNormal.razor
Normal file
@ -0,0 +1,100 @@
|
||||
@inject IBaiduOcr OcrService
|
||||
|
||||
<ButtonUpload TValue="string" OnChange="@OnClickToUpload" BrowserButtonText="VATInvoice" ShowUploadFileList="false"></ButtonUpload>
|
||||
|
||||
@if (Invoice != null)
|
||||
{
|
||||
<div class="row form-inline g-3 mt-0">
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票代码" @bind-Value="Invoice.InvoiceCode"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票号码" Value="Invoice.InvoiceNum"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票类型" @bind-Value="Invoice.ServiceType"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="联次信息" Value="Invoice.SheetNum"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票种类" @bind-Value="Invoice.InvoiceType"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票名称" Value="Invoice.InvoiceTypeOrg"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="发票标志" @bind-Value="Invoice.InvoiceTag"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="开票日期" Value="Invoice.InvoiceDate"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="购方名称" @bind-Value="Invoice.PurchaserName"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="纳税人识别号" Value="Invoice.PurchaserRegisterNum"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="开户行及账号" @bind-Value="Invoice.PurchaserBank"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="购方地址" Value="Invoice.PurchaserAddress"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="销售方名称" @bind-Value="Invoice.SellerName"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="纳税人识别号" Value="Invoice.SellerRegisterNum"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="销售方及账号" @bind-Value="Invoice.SellerBank"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="销售方地址" Value="Invoice.SellerAddress"></Display>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<Display ShowLabel="true" DisplayText="备注" @bind-Value="Invoice.Remarks"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="价税合计" Value="Invoice.AmountInFiguers"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="合计金额" Value="Invoice.TotalAmount"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="合计税额" @bind-Value="Invoice.TotalTax"></Display>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
</div>
|
||||
@if (Invoice.CommodityName?.Any() ?? false)
|
||||
{
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="税率" Value="Invoice.CommodityName.First().CommodityName"></Display>
|
||||
</div>
|
||||
}
|
||||
@if (Invoice.CommodityTaxRate?.Any() ?? false)
|
||||
{
|
||||
<div class="col-12 col-sm-6">
|
||||
<Display ShowLabel="true" DisplayText="税率" Value="Invoice.CommodityTaxRate.First().CommodityTaxRate"></Display>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private InvoiceEntity? Invoice { get; set; }
|
||||
|
||||
private async Task OnClickToUpload(UploadFile file)
|
||||
{
|
||||
if (file.File != null)
|
||||
{
|
||||
var payload = await file.GetBytesAsync(file.File.Size);
|
||||
if (payload?.Any() ?? false)
|
||||
{
|
||||
Invoice = await OcrService.CheckVatInvoiceAsync(payload);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using System;
|
||||
|
||||
namespace BootstrapBlazor.Shared.Demos.BaiduOcr;
|
||||
|
||||
/// <summary>
|
||||
/// 增值税发票识别示例
|
||||
/// </summary>
|
||||
public partial class BaiduOcrNormal
|
||||
{
|
||||
}
|
@ -532,11 +532,6 @@ internal static class MenusLocalizerExtensions
|
||||
Url = "qrcodes"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Text = Localizer["Recognizer"],
|
||||
Url = "recognizers"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Text = Localizer["Search"],
|
||||
Url = "searchs"
|
||||
@ -594,6 +589,12 @@ internal static class MenusLocalizerExtensions
|
||||
Url = "transitions"
|
||||
},
|
||||
new()
|
||||
{
|
||||
IsNew = true,
|
||||
Text = Localizer["BaiduOcr"],
|
||||
Url = "ocr"
|
||||
},
|
||||
new()
|
||||
{
|
||||
IsNew = true,
|
||||
Text = Localizer["VideoPlayer"],
|
||||
|
@ -559,6 +559,16 @@
|
||||
"NoRenderIntro": "By setting the <code>Editable=false</code> of the <code>IEditorItem</code> instance, the editable pop-up window cannot be edited.",
|
||||
"EditDialogOption": "EditDialogOption property"
|
||||
},
|
||||
"BootstrapBlazor.Shared.Samples.BaiduOcr": {
|
||||
"Title": "IBaiduOcr",
|
||||
"SubTitle": "Character recognition",
|
||||
"BasicUsageTitle": "VAT Invoice",
|
||||
"BasicUsageIntro": "Call Baidu Ocr interface for text recognition by uploading VAT invoice image",
|
||||
"BaiduOcrDesc": "本组件通过调用 Baidu AI 平台文字识别接口进行增值税发票文字识别。支持对增值税普票、专票、全电发票(新版全国统一电子发票,专票/普票)、卷票、区块链发票的所有字段进行结构化识别,包括发票基本信息、销售方及购买方信息、商品信息、价税信息等,其中五要素字段的识别准确率超过 99.9%; 同时,支持对增值税卷票的 21 个关键字段进行识别,包括发票类型、发票代码、发票号码、机打号码、机器编号、收款人、销售方名称、销售方纳税人识别号、开票日期、购买方名称、购买方纳税人识别号、项目、单价、数量、金额、税额、合计金额(小写)、合计金额(大写)、校验码、省、市,四要素字段的识别准确率可达95%。上传图片不能超过 4M",
|
||||
"BaiduOcrIntro": "Usage",
|
||||
"BaiduOcrStep1": "1. Get <code>IBaiduOcr</code> instance by inject service",
|
||||
"BaiduOcrStep2": "2. Call <code>IBaiduOcr</code> instance method"
|
||||
},
|
||||
"BootstrapBlazor.Shared.Demos.EditDialog.EditDialogNormal": {
|
||||
"LeftAlignedButton": "Edit popup (left-aligned)",
|
||||
"RightAlignedButton": "Edit popup (right aligned)"
|
||||
@ -4883,7 +4893,8 @@
|
||||
"Bluetooth": "Bluetooth & Printer",
|
||||
"PdfReader": "PDF Reader",
|
||||
"VideoPlayer": "VideoPlayer",
|
||||
"FileViewer": "FileViewer"
|
||||
"FileViewer": "FileViewer",
|
||||
"BaiduOcr": "IBaiduOcr "
|
||||
},
|
||||
"BootstrapBlazor.Shared.Samples.Table.TablesHeader": {
|
||||
"H1": "Header grouping function",
|
||||
|
@ -560,6 +560,16 @@
|
||||
"NoRenderIntro": "通过设置 <code>IEditorItem</code> 实例的 <code>Editable=false</code>, 实现编辑弹窗不可编辑此属性",
|
||||
"EditDialogOption": "EditDialogOption 属性"
|
||||
},
|
||||
"BootstrapBlazor.Shared.Samples.BaiduOcr": {
|
||||
"Title": "IBaiduOcr 百度文字识别服务",
|
||||
"SubTitle": "文字识别服务",
|
||||
"BasicUsageTitle": "增值税发票文字识别",
|
||||
"BasicUsageIntro": "通过上传增值税发票图片调用百度 Ocr 接口进行文字识别",
|
||||
"BaiduOcrDesc": "本组件通过调用 Baidu AI 平台文字识别接口进行增值税发票文字识别。支持对增值税普票、专票、全电发票(新版全国统一电子发票,专票/普票)、卷票、区块链发票的所有字段进行结构化识别,包括发票基本信息、销售方及购买方信息、商品信息、价税信息等,其中五要素字段的识别准确率超过 99.9%; 同时,支持对增值税卷票的 21 个关键字段进行识别,包括发票类型、发票代码、发票号码、机打号码、机器编号、收款人、销售方名称、销售方纳税人识别号、开票日期、购买方名称、购买方纳税人识别号、项目、单价、数量、金额、税额、合计金额(小写)、合计金额(大写)、校验码、省、市,四要素字段的识别准确率可达95%。上传图片不能超过 4M",
|
||||
"BaiduOcrIntro": "使用方法",
|
||||
"BaiduOcrStep1": "1. 通过注入服务获得 <code>IBaiduOcr</code> 实例",
|
||||
"BaiduOcrStep2": "2. 调用服务相对应的识别方法即可"
|
||||
},
|
||||
"BootstrapBlazor.Shared.Demos.EditDialog.EditDialogNormal": {
|
||||
"LeftAlignedButton": "编辑弹窗(左对齐)",
|
||||
"RightAlignedButton": "编辑弹窗(右对齐)"
|
||||
@ -4897,7 +4907,8 @@
|
||||
"Bluetooth": "蓝牙和打印 Bluetooth & Printer",
|
||||
"PdfReader": "PDF阅读器 PDF Reader",
|
||||
"VideoPlayer": "视频播放器 VideoPlayer",
|
||||
"FileViewer": "文件预览器 FileViewer"
|
||||
"FileViewer": "文件预览器 FileViewer",
|
||||
"BaiduOcr": "文字识别服务 IBaiduOcr "
|
||||
},
|
||||
"BootstrapBlazor.Shared.Samples.Table.TablesHeader": {
|
||||
"H1": "表头分组功能",
|
||||
|
17
src/BootstrapBlazor.Shared/Samples/BaiduOcr.razor
Normal file
17
src/BootstrapBlazor.Shared/Samples/BaiduOcr.razor
Normal file
@ -0,0 +1,17 @@
|
||||
@page "/ocr"
|
||||
@inject IStringLocalizer<BaiduOcr> Localizer
|
||||
|
||||
<h3>@Localizer["Title"]</h3>
|
||||
|
||||
<h4>@Localizer["SubTitle"]</h4>
|
||||
|
||||
<Tips class="mt-3">@Localizer["BaiduOcrDesc"]</Tips>
|
||||
|
||||
<PackageTips Name="BootstrapBlazor.BaiduOcr" />
|
||||
|
||||
<div class="mb-2"><b>@Localizer["BaiduOcrIntro"]</b></div>
|
||||
|
||||
<div>@((MarkupString)Localizer["BaiduOcrStep1"].Value)</div>
|
||||
<div>@((MarkupString)Localizer["BaiduOcrStep2"].Value)</div>
|
||||
|
||||
<DemoBlock Title="@Localizer["BasicUsageTitle"]" Introduction="@Localizer["BasicUsageIntro"]" Name="Normal" Demo="typeof(Demos.BaiduOcr.BaiduOcrNormal)" />
|
12
src/BootstrapBlazor.Shared/Samples/BaiduOcr.razor.cs
Normal file
12
src/BootstrapBlazor.Shared/Samples/BaiduOcr.razor.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Shared.Samples;
|
||||
|
||||
/// <summary>
|
||||
/// 百度文字识别示例
|
||||
/// </summary>
|
||||
public partial class BaiduOcr
|
||||
{
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
@page "/barcodereaders"
|
||||
@inject IStringLocalizer<BarcodeReaders> Localizer
|
||||
|
||||
|
||||
<h4>@Localizer["SubTitle"]</h4>
|
||||
|
||||
<PackageTips Name="BootstrapBlazor.BarCode" />
|
||||
|
@ -79,7 +79,8 @@
|
||||
"ribbontabs": "RibbonTabs",
|
||||
"pdfreaders": "PdfReaders",
|
||||
"videoPlayers": "VideoPlayers",
|
||||
"fileviewers": "FileViewers"
|
||||
"fileviewers": "FileViewers",
|
||||
"ocr": "BaiduOcr"
|
||||
},
|
||||
"video": {
|
||||
"autorefresh": "BV1ap4y1x7Qn?p=8",
|
||||
|
@ -82,142 +82,4 @@ public class UploadFile
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string? GetExtension() => Path.GetExtension(GetFileName());
|
||||
|
||||
/// <summary>
|
||||
/// 获取 base64 格式图片字符串
|
||||
/// </summary>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="maxWidth"></param>
|
||||
/// <param name="maxHeight"></param>
|
||||
/// <param name="maxAllowedSize"></param>
|
||||
/// <param name="token"></param>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public async Task RequestBase64ImageFileAsync(string format, int maxWidth, int maxHeight, long maxAllowedSize = 512000, CancellationToken token = default)
|
||||
{
|
||||
if (File != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imageFile = await File.RequestImageFileAsync(format, maxWidth, maxHeight);
|
||||
using var fileStream = imageFile.OpenReadStream(maxAllowedSize, token);
|
||||
using var memoryStream = new MemoryStream();
|
||||
await fileStream.CopyToAsync(memoryStream, token);
|
||||
PrevUrl = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}";
|
||||
Uploaded = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Code = 1004;
|
||||
Error = ex.Message;
|
||||
PrevUrl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="maxWidth"></param>
|
||||
/// <param name="maxHeight"></param>
|
||||
/// <param name="maxAllowedSize"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public async Task<byte[]?> GetByteArray(string format, int maxWidth, int maxHeight, long maxAllowedSize = 512000, CancellationToken token = default)
|
||||
{
|
||||
if (File != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imageFile = await File.RequestImageFileAsync(format, maxWidth, maxHeight);
|
||||
using var fileStream = imageFile.OpenReadStream(maxAllowedSize, token);
|
||||
using var memoryStream = new MemoryStream();
|
||||
await fileStream.CopyToAsync(memoryStream, token);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Code = 1004;
|
||||
Error = ex.Message;
|
||||
PrevUrl = null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存到文件
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="maxAllowedSize"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public async Task<bool> SaveToFile(string fileName, long maxAllowedSize = 512000, CancellationToken token = default)
|
||||
{
|
||||
var ret = false;
|
||||
if (File != null)
|
||||
{
|
||||
// 文件保护,如果文件存在则先删除
|
||||
if (System.IO.File.Exists(fileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
System.IO.File.Delete(fileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Code = 1002;
|
||||
Error = ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
var folder = Path.GetDirectoryName(fileName);
|
||||
if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
|
||||
if (Code == 0)
|
||||
{
|
||||
using var uploadFile = System.IO.File.OpenWrite(fileName);
|
||||
|
||||
try
|
||||
{
|
||||
// 打开文件流
|
||||
var stream = File.OpenReadStream(maxAllowedSize, token);
|
||||
|
||||
var buffer = new byte[4 * 1096];
|
||||
int bytesRead = 0;
|
||||
double totalRead = 0;
|
||||
|
||||
// 开始读取文件
|
||||
while ((bytesRead = await stream.ReadAsync(buffer, token)) > 0)
|
||||
{
|
||||
totalRead += bytesRead;
|
||||
await uploadFile.WriteAsync(buffer.AsMemory(0, bytesRead), token);
|
||||
|
||||
if (UpdateCallback != null)
|
||||
{
|
||||
var percent = (int)((totalRead / File.Size) * 100);
|
||||
if (percent > ProgressPercent)
|
||||
{
|
||||
ProgressPercent = percent;
|
||||
UpdateCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Uploaded = true;
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Code = 1003;
|
||||
Error = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// BaiduOcrOption 配置类
|
||||
/// </summary>
|
||||
public class BaiduOcrOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 Baidu AppId
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 Baidu ApiKey
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? ApiKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 Baidu 密钥
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? Secret { get; set; }
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageTags>Bootstrap Blazor Baidu Ocr Components</PackageTags>
|
||||
<Description>Bootstrap UI components extensions of Baidu Ocr</Description>
|
||||
<RootNamespace>BootstrapBlazor.Components</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Baidu.AI" Version="4.15.10" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,32 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// BootstrapBlazor 服务扩展类
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加百度文字识别服务
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configOptions"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddBootstrapBlazorBaiduOcr(this IServiceCollection services, Action<
|
||||
BaiduOcrOption>? configOptions = null)
|
||||
{
|
||||
services.TryAddSingleton<IBaiduOcr, BaiduOcr>();
|
||||
services.AddOptionsMonitor<BaiduOcrOption>();
|
||||
services.Configure<BaiduOcrOption>(option =>
|
||||
{
|
||||
configOptions?.Invoke(option);
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 货物信息实体类
|
||||
/// </summary>
|
||||
public class CommodityEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 行号
|
||||
/// </summary>
|
||||
public string? Row { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 货物名称内容
|
||||
/// </summary>
|
||||
[JsonProperty("word")]
|
||||
public string? CommodityName { get; set; }
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 税率信息实体类
|
||||
/// </summary>
|
||||
public class CommodityTaxRateEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 行号
|
||||
/// </summary>
|
||||
public string? Row { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 税率内容
|
||||
/// </summary>
|
||||
[JsonProperty("word")]
|
||||
public string? CommodityTaxRate { get; set; }
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 发票实体类
|
||||
/// </summary>
|
||||
public class InvoiceEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 发票消费类型
|
||||
/// </summary>
|
||||
public string? ServiceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 联次信息。专票第一联到第三联分别输出:第一联:记账联、第二联:抵扣联、第三联:发票联;普通发票第一联到第二联分别输出:第一联:记账联、第二联:发票联
|
||||
/// </summary>
|
||||
public string? SheetNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 发票种类。不同类型发票输出:普通发票、专用发票、电子普通发票、电子专用发票、通行费电子普票、区块链发票、通用机打电子发票、电子发票(专用发票)、电子发票(普通发票)
|
||||
/// </summary>
|
||||
public string? InvoiceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 发票名称
|
||||
/// </summary>
|
||||
public string? InvoiceTypeOrg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 发票代码
|
||||
/// </summary>
|
||||
public string? InvoiceCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 发票号码
|
||||
/// </summary>
|
||||
public string? InvoiceNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 增值税发票左上角标志。 包含:通行费,销项负数、代开、收购、成品油、其他
|
||||
/// </summary>
|
||||
public string? InvoiceTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 开票日期
|
||||
/// </summary>
|
||||
public string? InvoiceDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 机打号码。仅增值税卷票含有此参数
|
||||
/// </summary>
|
||||
public string? MachineNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 机器编号。仅增值税卷票含有此参数
|
||||
/// </summary>
|
||||
public string? MachineCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 校验码。增值税专票无此参数
|
||||
/// </summary>
|
||||
public string? CheckCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 购方名称
|
||||
/// </summary>
|
||||
public string? PurchaserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 购方纳税人识别号
|
||||
/// </summary>
|
||||
public string? PurchaserRegisterNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 购方地址及电话
|
||||
/// </summary>
|
||||
public string? PurchaserAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 购方开户行及账号
|
||||
/// </summary>
|
||||
public string? PurchaserBank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 密码区
|
||||
/// </summary>
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 省
|
||||
/// </summary>
|
||||
public string? Province { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 市
|
||||
/// </summary>
|
||||
public string? City { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否代开
|
||||
/// </summary>
|
||||
public string? Agent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 备注
|
||||
/// </summary>
|
||||
public string? Remarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 销售方名称
|
||||
/// </summary>
|
||||
public string? SellerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 销售方地址及电话
|
||||
/// </summary>
|
||||
public string? SellerAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 销售方开户行及账号
|
||||
/// </summary>
|
||||
public string? SellerBank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 销售方纳税人识别号
|
||||
/// </summary>
|
||||
public string? SellerRegisterNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 合计金额
|
||||
/// </summary>
|
||||
public string? TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 合计税额
|
||||
/// </summary>
|
||||
public string? TotalTax { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 价税合计(大写)
|
||||
/// </summary>
|
||||
public string? AmountInWords { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 价税合计(小写)
|
||||
/// </summary>
|
||||
public string? AmountInFiguers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 收款人
|
||||
/// </summary>
|
||||
public string? Payee { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 复核
|
||||
/// </summary>
|
||||
public string? Checker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 开票人
|
||||
/// </summary>
|
||||
public string? NoteDrawer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 货物名称
|
||||
/// </summary>
|
||||
public List<CommodityEntity>? CommodityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 税率
|
||||
/// </summary>
|
||||
public List<CommodityTaxRateEntity>? CommodityTaxRate { get; set; }
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using Baidu.Aip.Ocr;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
internal class BaiduOcr : IBaiduOcr
|
||||
{
|
||||
protected IOptionsMonitor<BaiduOcrOption> Options { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public BaiduOcr(IOptionsMonitor<BaiduOcrOption> options)
|
||||
{
|
||||
Options = options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 身份证识别
|
||||
/// </summary>
|
||||
public void Scan(byte[] image)
|
||||
{
|
||||
var client = new Ocr(Options.CurrentValue.ApiKey, Options.CurrentValue.Secret);
|
||||
client.GeneralBasic(image);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 识别增值税发票方法
|
||||
/// </summary>
|
||||
public Task<InvoiceEntity> CheckVatInvoiceAsync(byte[] image) => Task.Run(() =>
|
||||
{
|
||||
var client = new Ocr(Options.CurrentValue.ApiKey, Options.CurrentValue.Secret);
|
||||
var resp = client.VatInvoice(image);
|
||||
var ret = resp.GetValue("words_result").ToObject(typeof(InvoiceEntity)) as InvoiceEntity;
|
||||
return ret ?? new InvoiceEntity() { CommodityName = new(), CommodityTaxRate = new() };
|
||||
});
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 百度文字识别服务
|
||||
/// </summary>
|
||||
public interface IBaiduOcr
|
||||
{
|
||||
/// <summary>
|
||||
/// 增值税发票识别
|
||||
/// </summary>
|
||||
/// <param name="image"></param>
|
||||
Task<InvoiceEntity> CheckVatInvoiceAsync(byte[] image);
|
||||
}
|
BIN
src/Extensions/Components/BootstrapBlazor.BaiduOcr/logo.png
Normal file
BIN
src/Extensions/Components/BootstrapBlazor.BaiduOcr/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 378 B |
@ -0,0 +1,6 @@
|
||||
// This is a JavaScript module that is loaded on demand. It can export any number of
|
||||
// functions, and may import other JavaScript modules if required.
|
||||
|
||||
export function showPrompt(message) {
|
||||
return prompt(message, 'Type anything here');
|
||||
}
|
@ -57,7 +57,7 @@ public class BaiduRecognizerProvider : IRecognizerProvider, IAsyncDisposable
|
||||
if (Module == null)
|
||||
{
|
||||
var moduleName = "./_content/BootstrapBlazor.BaiduSpeech/js/recognizer.js";
|
||||
Logger.LogInformation($"load module {moduleName}");
|
||||
Logger.LogInformation("load module {moduleName}", moduleName);
|
||||
Module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", moduleName);
|
||||
}
|
||||
Interop ??= DotNetObjectReference.Create(this);
|
||||
@ -71,7 +71,7 @@ public class BaiduRecognizerProvider : IRecognizerProvider, IAsyncDisposable
|
||||
[JSInvokable]
|
||||
public async Task RecognizeCallback(RecognizerStatus status, byte[]? bytes)
|
||||
{
|
||||
Logger.LogInformation($"RecognizerStatus: {status}");
|
||||
Logger.LogInformation("RecognizerStatus: {status}", status);
|
||||
string data = "";
|
||||
if (status == RecognizerStatus.Finished)
|
||||
{
|
||||
@ -89,11 +89,11 @@ public class BaiduRecognizerProvider : IRecognizerProvider, IAsyncDisposable
|
||||
sb.Append(item.ToString());
|
||||
}
|
||||
data = sb.ToString();
|
||||
Logger.LogInformation($"recognizer: {data}");
|
||||
Logger.LogInformation("recognizer: {data}", data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogError($"err_no: {err_no}");
|
||||
Logger.LogError("err_no: {err_no}", err_no);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user