61.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--提取金额 - 实践

news/2025/9/26 9:38:52/文章来源:https://www.cnblogs.com/lxjshuju/p/19112886

在前一篇文章中,我们已经成功地利用百度OCR技术识别了图片中的文字内容,实现了图片到文本的初步转换。然而,实际的记账场景中,用户往往更关心图片中所包含的金额信息。因此,在本篇文章中,我们将进一步完善这一功能,重点介绍如何从OCR识别的结果中准确提取出金额数据,并将其作为结构化信息返回给调用方。

一、设置提取金额 Prompt

为了提高金额提取的准确性,我们需要设置一个专门提取文字内容中总金额的Prompt,指导AI识别和提取金额信息。

1.1 什么是 Prompt

Prompt,中文常译为“提示词”或“提示语”,是在与人工智能模型(如大语言模型或OCR后处理模型)交互时,用户用来引导模型生成特定内容或执行特定任务的文本指令。通过精心设计的Prompt,可以让AI更好地理解用户的意图,从而输出更符合需求的结果。在金额提取的场景中,Prompt可以明确告诉AI需要关注文本中的金额信息,并以特定格式返回。例如,可以这样设置Prompt:“请从以下文本中提取出所有出现的金额,并以列表形式返回。”这样的指令能够帮助AI聚焦于金额相关的数据,提升提取的准确率和效率。通过不断优化和调整Prompt内容,可以进一步提升AI在实际应用中的表现。

1.2 使用 PromptPilot 优化 Prompt

在实际应用中,设计一个有效的Prompt可能需要反复试验和调整。为此,我们可以借助PromptPilot工具来优化我们的Prompt。PromptPilot是一款专门用于Prompt设计和优化的工具,它可以帮助我们测试不同的Prompt版本,并分析其效果,从而找到最适合我们需求的Prompt。

在本次金额提取的场景中,我们可以使用PromptPilot来测试不同的Prompt设计,观察它们在提取金额时的表现。通过不断调整Prompt的措辞和结构,我们可以逐步优化其效果,确保AI能够准确地识别和提取出文本中的金额信息。最终,我们将选择一个经过优化的Prompt,用于实际的金额提取任务。

我们首先进入到PromptPilot的首页,点击 帮我生成一个Prompt 按钮,进入到Prompt生成页面,如下图:
在这里插入图片描述

接着,我们在Prompt生成页面中,输入我们初步设计的Prompt内容,提取输入内容中的总金额和消费类型,如果带有货币符号将其转换为标准的货币简称,常见货币符号按照标准简称转换,如 $ 转换为 USD,£ 转换为 GBP,€ 转换为 EUR 等,输出格式是:{“amount”:xxx,“category”:xxx,“currency”:xxx},然后选择类型为文本理解,之后点击小飞机按钮,提交生成请求,如下图:
在这里插入图片描述

在等待几秒钟后,PromptPilot会展示生成出来的Prompt结果,我们可以看到生成的Prompt内容与我们输入的意思基本一致,说明我们的初步设计已经比较符合要求。接着,我们点击页面右下角的验证Prompt 按钮进行验证Prompt的效果。由于我们的专栏并非专门的AI技术专栏,因此我们这里就不再赘述如何验证Prompt的效果,以及如何调优Prompt,感兴趣的读者可以参考相关的文档进行学习和实践。经过一番调优后,我们最终确定了一个较为满意的Prompt,用于后续的金额提取任务。这是我们最终确定的Prompt内容:你的任务是从输入内容中提取总金额和消费类型,并将带有货币符号的金额转换为标准的货币简称。在处理过程中,需要将常见货币符号按照标准简称进行转换,消费类型必须是中文,例如 $ 转换为 USD,£ 转换为 GBP,€ 转换为 EUR 等。请按照以下格式输出结果:{“amount”:xxx,“category”:xxx,“currency”:xxx},我们将这段Prompt内容保存到Nacos配置中心的SP.ResourceService配置中,如下所示:

"Prompts":{
"OCRAmount":"你的任务是从输入内容中提取总金额和消费类型,并将带有货币符号的金额转换为标准的货币简称。在处理过程中,需要将常见货币符号按照标准简称进行转换,消费类型必须是中文,例如 $ 转换为 USD,£ 转换为 GBP,€ 转换为 EUR 等。\r\n请按照以下格式输出结果:\r\n{\"amount\":xxx,\"category\":xxx,\"currency\":xxx}"
},

二、实现提取金额功能

有了优化后的Prompt,我们接下来就可以实现提取金额的功能了。我们将创建一个新的API接口/api/assistant/extract-amount-and-category,用于接收OCR识别出来的文本内容,并返回提取出来的金额信息。

2.1 Service 实现

首先我们在SP.ResourceService项目中,创建一个新的服务接口IAssistantService,在它里面定义提取金额的方法ExtractAmountAndCategoryAsync,代码如下所示:

using SP.ResourceService.Models.Response;
namespace SP.ResourceService.Service;
/// <summary>/// AI助手服务
/// </summary>
public interface IAssistantService
{
/// <summary>/// 提取文字中的金额和消费类型
/// </summary>
/// <param name="text">文字内容</param>
/// <returns>金额和消费类型</returns>
Task<AmountAndCategoryExtractionResponse> ExtractAmountAndCategoryAsync(string text);}

在接口定义完成后,我们需要实现具体的业务逻辑。在 SP.ResourceService.Service.Impl 中新建 DeepSeekAssistantServiceImpl 类,实现 IAssistantService 接口。在该实现类中,ExtractAmountAndCategoryAsync 方法会接收OCR识别得到的文本内容,随后调用 DeepSeek 模型进行处理,提取出文本中的总金额、消费类型以及货币信息。这一步可以通过调用 DeepSeek 服务的API接口来完成,将文本和Prompt一同发送给AI服务,获取结构化的提取结果。收到AI返回的数据后,我们需要对其进行解析,然后将这些数据封装到 AmountAndCategoryExtractionResponse 响应模型中返回。这样,整个金额提取的服务端逻辑就完成了。代码如下:

using System.Text.Json;
using Microsoft.Extensions.Options;
using RestSharp;
using SP.ResourceService.Models.Config;
using SP.ResourceService.Models.Enumeration;
using SP.ResourceService.Models.AI.DeepSeek;
using SP.ResourceService.Models.Response;
namespace SP.ResourceService.Service.Impl;
/// <summary>/// DeepSeek助手服务实现
/// </summary>
public class DeepSeekAssistantServiceImpl
: IAssistantService
{
/// <summary>/// 提示词配置选项
/// </summary>
private readonly PromptsOptions _promptsOptions;
/// <summary>/// DeepSeek 配置选项
/// </summary>
private readonly DeepSeekOptions _deepSeekOptions;
private readonly ILogger<DeepSeekAssistantServiceImpl> _logger;/// <summary>/// 构造函数/// </summary>
/// <param name="promptsOptions"></param>
/// <param name="deepSeekOptions"></param>
/// <param name="logger"></param>public DeepSeekAssistantServiceImpl(IOptions<PromptsOptions> promptsOptions,IOptions<DeepSeekOptions> deepSeekOptions, ILogger<DeepSeekAssistantServiceImpl> logger){ValidatePromptsConfiguration(promptsOptions.Value);ValidateDeepSeekConfiguration(deepSeekOptions.Value);_promptsOptions = promptsOptions.Value;_deepSeekOptions = deepSeekOptions.Value;_logger = logger;}/// <summary>/// 提取文字中的金额和消费类型/// </summary>/// <param name="text">文字内容</param>/// <returns>金额和消费类型</returns>public async Task<AmountAndCategoryExtractionResponse> ExtractAmountAndCategoryAsync(string text){string url = _deepSeekOptions.BaseUrl + _deepSeekOptions.Chat;string apiKey = _deepSeekOptions.APIKey;var options = new RestClientOptions(url){MaxTimeout = -1,};var client = new RestClient(options);var request = new RestRequest(url, Method.Post);request.AddHeader("Content-Type", "application/json");request.AddHeader("Accept", "application/json");request.AddHeader("Authorization", "Bearer " + apiKey);// 构造请求体RequestData requestData = new RequestData();// 新建角色Message systemMessage = new Message();systemMessage.Content = _promptsOptions.OCRAmount;systemMessage.Role = AIRole.System;List<Message> messages = new List<Message>();Message userMessage = new Message();userMessage.Content = text;userMessage.Role = AIRole.User;messages.Add(systemMessage);messages.Add(userMessage);requestData.Messages = messages;requestData.Temperature = 0.7d;string body = JsonSerializer.Serialize(requestData);request.AddStringBody(body, DataFormat.Json);RestResponse response = await client.ExecuteAsync(request);DeepSeekChatResponse deepSeekChatResponse = JsonSerializer.Deserialize<DeepSeekChatResponse>(response.Content);List<Choice> choices = deepSeekChatResponse.Choices;if (choices != null && choices.Count >0){_logger.LogInformation(response.Content);string content = choices[0].Message.Content;AmountAndCategoryExtractionResponse result = JsonSerializer.Deserialize<AmountAndCategoryExtractionResponse>(content);return result;}else{_logger.LogError("DeepSeek未返回有效的回答,"+response.Content);return new AmountAndCategoryExtractionResponse();}}/// <summary>/// 校验Prompts参数/// </summary>/// <param name="promptsOptions"></param>private void ValidatePromptsConfiguration(PromptsOptions promptsOptions){if (string.IsNullOrWhiteSpace(promptsOptions.OCRAmount)){throw new ArgumentException("OCR金额提示词不能为空");}}/// <summary>/// 校验DeepSeek参数/// </summary>/// <param name="deepSeekOptions"></param>/// <exception cref="NotImplementedException"></exception>private void ValidateDeepSeekConfiguration(DeepSeekOptions deepSeekOptions){if (string.IsNullOrWhiteSpace(deepSeekOptions.APIKey)){throw new ArgumentException("DeepSeek API Key不能为空");}if (string.IsNullOrWhiteSpace(deepSeekOptions.BaseUrl)){throw new ArgumentException("DeepSeek BaseUrl不能为空");}if (string.IsNullOrWhiteSpace(deepSeekOptions.Chat)){throw new ArgumentException("DeepSeek Chat地址不能为空");}}}

DeepSeekAssistantServiceImpl类是一个专门用于与DeepSeek AI服务进行交互的实现类,它承担着从用户输入的文本中智能提取金额和分类信息的核心功能。在构造函数里接收多个依赖项,包括HTTP客户端工厂、日志记录器以及两个配置选项对象。HTTP客户端工厂用于创建与DeepSeek API通信的HTTP客户端,确保网络请求的可靠性和性能。日志记录器则负责记录整个处理过程中的关键信息和错误,便于后续的问题排查和系统监控。两个配置选项对象分别是PromptsOptionsDeepSeekOptions,前者包含了与AI交互时使用的提示词模板,后者则包含了DeepSeek服务的连接配置信息,如API密钥、基础URL等。在类的初始化过程中,构造函数会立即调用ValidatePromptsConfigurationValidateDeepSeekConfiguration这两个验证方法来验证配置的完整性和正确性。

核心的业务逻辑集中在ExtractAmountAndCategoryAsync方法中,这个方法首先会验证输入参数的有效性,然后构建发送给DeepSeek API的请求体,这个请求体采用了标准的OpenAI兼容格式,包含模型名称、消息数组和其他参数。在消息构建过程中,系统会将预配置的提示词模板与用户输入的文本进行组合,形成完整的AI指令。对于HTTP请求的发送过程,方法会创建一个HTTP客户端实例,设置必要的请求头信息,包括授权令牌和内容类型,然后通过POST方法发送到DeepSeek。整个网络通信过程都被包装在异常处理机制中,确保网络错误或服务异常不会导致整个应用程序崩溃。在收到响应时,首先会检查HTTP响应的状态码,确保请求成功执行。然后对响应内容进行JSON反序列化,提取出AI生成的回答。由于AI服务的返回结果可能存在不确定性,代码会验证返回的选择列表是否包含有效内容。如果AI成功返回了结果,系统会进一步解析其中的结构化数据,将其转换为应用程序可以使用的AmountAndCategoryExtractionResponse对象。错误处理和日志记录贯穿于整个处理流程,当AI服务没有返回有效回答时,会记录详细的错误信息,包括原始的响应内容,并且系统会返回一个空的响应对象,而不是抛出异常,确保调用方不会因为AI服务的问题而影响整个业务流程。

私有配置验证方法ValidatePromptsConfiguration方法验证了OCR金额提示词配置的完整性,ValidateDeepSeekConfiguration方法则验证DeepSeek服务连接所需的所有关键参数,包括API密钥、基础URL和聊天接口地址。

2.2 Controller 实现

在 Controller 层的实现中,我们只需注入前面实现的 IAssistantService,然后在对应的 API 方法中调用 ExtractAmountAndCategoryAsync 方法即可。具体来说,可以在 AssistantController 中新增一个 POST 接口 /api/assistant/extract-amount-and-category,该接口接收 OCR 识别后的文本内容作为请求体,通过调用服务层的方法完成金额和消费类型的提取,并将结构化的结果返回给前端。代码如下:

using Microsoft.AspNetCore.Mvc;
using SP.ResourceService.Service;
namespace SP.ResourceService.Controllers
{
/// <summary>/// AI助手控制器
/// </summary>
[Route("api/assistant")]
[ApiController]
public class AssistantController
: ControllerBase
{
/// <summary>/// AI助手服务
/// </summary>
private readonly IAssistantService _assistantService;
/// <summary>/// 构造函数
/// </summary>
/// <param name="assistantService"></param>
public AssistantController(IAssistantService assistantService)
{
_assistantService = assistantService;
}
/// <summary>/// 提取文字中的金额和消费类型
/// </summary>
/// <param name="text">文字内容</param>
/// <returns>金额和消费类型</returns>
[HttpPost("extract-amount-and-category")]
public async Task<IActionResult> ExtractAmountAndCategory([FromBody] string text){var result = await _assistantService.ExtractAmountAndCategoryAsync(text);return Ok(result);}}}

在上述代码中,我们定义了一个新的API控制器AssistantController,它包含一个POST方法ExtractAmountAndCategory,该方法接收OCR识别后的文本内容作为输入参数。通过调用注入的IAssistantService服务的ExtractAmountAndCategoryAsync方法,我们能够将文本内容传递给服务层进行处理,并获取提取出来的金额和消费类型。最后,使用Ok(result)将结果以HTTP 200状态码返回给前端调用方。

三、总结

至此,我们已经完成了从OCR识别结果中提取金额和消费类型的功能实现。通过调用新的API接口/api/assistant/extract-amount-and-category,我们可以将OCR识别得到的文本内容发送给后端服务,后端会利用DeepSeek模型进行处理,并返回结构化的金额和消费类型信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918056.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Ansible 部署 Elasticsearch 集群

使用 Ansible 部署 Elasticsearch 集群1. 集群规划 1.1 服务器列表IP 主机名 内存(GB) CPU核数 磁盘 操作系统 CPU 架构 备注11.0.0.11 arc-dev-dc01 8 1 500GB CentOS 7.9.2009 x86_64 Ansible 管理机,无法访问互联…

免费无广告!这款开源工具让文件转换像复制粘贴一样简单!

FileConverter —— 一个非常简单的工具,通过使用 Windows 资源管理器的上下文菜单转换和压缩一个或多个文件。大家好,我是 Java陈序员。 之前,给大家介绍一款格式转换全能王,支持超过一千多种的文件格式转换。 格…

时序InSAR形变结果合并操作说明 - ENVI

采用PS-InSAR或SBAS-InSAR对同一个地区得到不同时间段内的形变结果,有时候我们需要将这些不同时间段内形变结果进行合并,得到以最早时间点为基准、覆盖整个时间跨度的形变结果。 SARscape从5.5.3版本开始提供栅格或矢…

建设网站的基本技术网络规划设计师教程pdf

主题 进程同步与进程互斥 01进程同步 问题在多道批处理系统中&#xff0c;多个进程是并发执行的&#xff0c;而并发执行的进程具有异步性&#xff0c;也就是说&#xff0c;各个进程以各自独立的、不可预知的速度向前推进。这样会带来什么问题呢&#xff1f;如果有 AB…

北京建网站需要多少钱动漫网站html

一、 python语法 1. 请说一下你对迭代器和生成器的区别&#xff1f; 2. 什么是线程安全&#xff1f; 3. 你所遵循的代码规范是什么&#xff1f;请举例说明其要求&#xff1f; 4. Python中怎么简单的实现列表去重&#xff1f; 5. python 中 yield 的用法…

深圳seo网站优化公司360公司官网首页

Unity3D 小案例 像素贪吃蛇 第二期 蛇的觅食 像素贪吃蛇 食物生成 在场景中创建一个 2D 正方形&#xff0c;调整颜色&#xff0c;添加 Tag 并修改为 Food。 然后拖拽到 Assets 文件夹中变成预制体。 创建食物管理器 FoodManager.cs&#xff0c;添加单例&#xff0c;可以设置…

网站建设软硬件要求江西省建设招标网站

一 ISN序列号探究 本文主要探究三次握手建立TCP连接的细节备注&#xff1a; 某些问题探究的比较深入,当前用不到,暂时通过链接引入进来吃水不忘挖井人&#xff1a; 小林 coding ① 初始序列号 ISN 是如何随机产生的 ISN: 初始化序列号 Initial Sequence Number 接收方和…

在Vue.js中设置方法时访问$vuetify实例

在Vue.js中访问 $vuetify实例通常意味着你正在使用Vuetify框架,它是一个流行的Vue.js的UI框架。要在Vue组件的方法中访问 $vuetify实例,通常是在组件的实例方法中通过 this关键字来实现。 例如,你可能会在Vue组件中…

纷享销客CRM任务系统:破解快消品终端动销管理难题

品牌商自有销售人员做动销,成本越来越高,雇不起那么多人,转而与经销商合作,但如何让他们的销售更主动、更多地卖自己的产品呢? 一线人员到底有没有按时拜访?陈列合不合格?促销有没有执行到位?看不见、摸不着、…

第一周博客作业-介绍自己

自我介绍: 大家好,我叫苏紫先,是2023级数据科学与大数据技术0102班的一名学生,很高兴进入这个大家庭并在此记录我接下来的学习内容,如今进入大学已经3年了,我们上了很多专业的科目虽然说成绩不错,但是真实掌握的…

完整教程:zookeeper+kafka

完整教程:zookeeper+kafka2025-09-26 09:22 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; …

AI大模型应用简介 - 努力-

AI大模型应用简介AI大模型简介一、AI大模型简介2022年11月30日,OpenAI公司发布了GPT3.5模型,同时对外开放了ChatGPT产品。人工智能突然进入了普通人的生活中,各种AI应用如雨后春笋般出现。不过,由于大模型研究的成…

完整教程:01_5分钟运行你的第一个LLM:Hugging Face入门

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

codeforces 1504 div3

codeforces 1504 div3codeforces 1054 div3 D 就是枚举最后答案的所有可能就好了,aba,bab ... 赛时没想到怎么算花费,结果在这题上码死了, 这种花费真心不擅长算,只知道批处理,子数组思维,没有动态的思路,这个就…

React 基础核心概念(8 个)——从入门到能写业务组件(上)| 葡萄城技术团队

React 基础核心概念(8 个)——从入门到能写业务组件(上) 前言:为什么要先掌握这些基础概念? 对国内开发者来说,React 是开发中后台系统、电商前端、移动端 H5 的“刚需技能”。但很多人刚学就陷入“会写 JSX 却…

2 day - when

第二天嘿嘿 从今天开始应用一些方法 法一、链式时延协议(嘿嘿这个时延还有协议真的很容易让人联想到计网,很喜欢计网老师) 有两条任务链为主链和辅助链。启用时,可以启用辅助链,预约一个信号:摘下眼镜并给小号发…

玄武建设局网站网页设计方案

NoSQL数据库&#xff1a;数据的一致性 读取一致性 强一致性 在任何时间访问集群中任一结点&#xff0c;得到的数据结果一致&#xff1b; 用户一致性 对同一用户&#xff0c;访问集群期间得到的数据一致&#xff1b; 解决用户一致性&#xff1a;使用粘性会话&#xff0c;将会话…

可以将自己做的衣服展示的网站网站的流量建设

文章目录 0 前言1 常用的分类网络介绍1.1 CNN1.2 VGG1.3 GoogleNet 2 图像分类部分代码实现2.1 环境依赖2.2 需要导入的包2.3 参数设置(路径&#xff0c;图像尺寸&#xff0c;数据集分割比例)2.4 从preprocessedFolder读取图片并返回numpy格式(便于在神经网络中训练)2.5 数据预…

网站怎么更新数据重庆网架加工厂

华子目录 概念工作流程工作图流程&#xff08;按行处理&#xff09; awk程序执行方式1.通过命令行执行awk程序实例 2.awk命令调用脚本执行实例 3.直接使用awk脚本文件调用实例 awk命令的基本语法格式BEGIN模式与END模式实例awk的输出 记录和域&#xff08;记录表示数据行&#…

机械网站开发铁路局招聘正式工4000人

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…