招募活动投稿展示 | 感受科技温度,从一个 LLM 应用开始

c91e7129813a1c1f3232abac5ad7709d.png

活动介绍

谷歌开发者招募活动是专为 Google 技术的爱好者及开发者们开展的活动,旨在鼓励大家通过多种形式 (文章/视频/coding 等) 创作与 Google 技术相关的讲解分享、实践案例或活动感受等内容,展示代码、框架、平台在真实世界中的生动表现,以及分享您应用 AI 技术的故事经历与成果。

作者简介

本文作者 Jax,从事 Web 开发工作已有 7 年,也从中获得了很多乐趣。

文章导读

源自近期的观察和思考,作者萌生了借助 AI 为老年人提供关怀的想法。在谷歌开发者社区举办的 Gemma Hackathon 中将自己的想法付诸了实践,打造了一款 "药童" 的 Web 应用,巧用 LLM 特性帮助老年人轻松读懂药品说明书,展示了科技世界的温度。

*以下为投稿原文,有改动

引言

"变老很糟糕 (Getting old sucks)",这是电影《勇敢者的游戏》里的一句台词。据统计,截止 2023 年底,60 岁以上人口占全国总人口的 21.1%。若干年后,这个比重可能会更大,而我们自己也将成为构成这一比重的分子之一。如何帮助老年人活得更舒适一些?如何帮助若干年以后的我们自己?是我最近在思考的问题。

某天偶然间,我看到谷歌开发者社区将举办 Gemma 黑客松开发者竞赛,鼓励开发者基于 Gemma 模型技术来展示科技温度。这几乎在一瞬间就激发了我的灵感 —— LLM 擅长处理大段文字,这不正适合用来帮老年人提升阅读体验吗?对视力不好,甚至识字不全的长辈来说,当身边无人帮助时,吃药之前读说明书往往是非常困难的事情。用大语言模型来处理药品说明书的文字内容,并以语音问答的形式来辅助理解,无论是从技术可行性还是用户友好性的角度来考虑,似乎都非常合理!

于是,热爱编程的我和队友在竞赛中完成了我们的作品 —— 药童,一个帮助爷爷奶奶们读懂药品说明书的 Web 应用。

△ 作品演示

如录屏视频所示,爷爷奶奶们只需要用手机拍下药品说明书,然后就可以像语音聊天一样了解药品的信息了。这样的极简交互,尽可能地降低了学习和操作成本,让用户可以即开即用。

接下来,我将会从技术实现层面拆解各个模块,希望其中的点滴也能激发你的灵感。你将会看到 OCR、RAG、ASR、TTS…… 如果你对这些名词不太了解,别急,且听我娓娓道来。

技术实现

从用户上传照片,到回复用户的提问,其背后的处理流程是这样的:

74c2e010d21a924dd6cf01b970fcc605.png

  1. 从图片中提取文字内容;

  2. 将提取出的文本内容切分、向量化,存储到向量数据库中;

  3. 用户发送语音问题后,把语音转为文字格式;

  4. 将问题文本与向量数据库进行匹配,检索出高相关度的知识块;

  5. 将相关知识上下文与问题文本一起包装成提示词,发送给 LLM;

  6. LLM 根据提示词生成文本格式的回答内容;

  7. 将回答文本转化为语音,播放给用户听。

OCR: 从图片提取文字

想要提取图片中的文字,有多种方式可以实现,我了解到的有两个方向: 一个是经典的光学字符识别 (Optical Character Recognition) 思路,比如 Tesseract、PaddleOCR 等;另一个则是视觉问答 (Visual Question Answering) 模式,多模态的 Gemini API*、PaliGemma 等都有能力做到。

*适用于出海开发者

  • Tesseract

    https://github.com/tesseract-ocr/tesseract

  • PaddleOCR

    https://github.com/PaddlePaddle/PaddleOCR

  • Gemini

    https://gemini.google.com/

  • PaliGemma

    https://huggingface.co/google/paligemma-3b-ft-ocrvqa-896

在比赛时间有限的情况下,我选择了个人比较熟悉的 PaddleOCR。处理过程的核心逻辑如下:

```python
# 开启方向检测、设置语言
ocr = PaddleOCR(use_angle_cls=True, lang="ch")# 传入图片的文件路径
result = ocr.ocr(img, cls=True)# 逐行输出识别结果
for idx in range(len(result)):res = result[idx]for line in res:print('py_ocr_res', line[1][0])
```

得到识别结果后,将文本内容传递给向量化服务。

向量化存储

现在我们有了说明书文本内容,那么如何让 LLM 基于这些文本内容去回答用户的问题呢?

我们当然可以把说明书内容整个嵌在提示词里,要求 LLM 根据这些内容作答。但引发的问题就是,在每一轮对话中,LLM 都要处理全量的文本,会降低生成速度和质量,进而影响用户体验。因此,我们需要检索增强式生成 (Retrieval-Augmented Generation,RAG),也就是把问题以及和问题相关度高的知识一起发送给 LLM,帮助 LLM 快速而准确地生成回答。

在这一环节,我们要先把通过 OCR 提取出来的文本进行处理,搭建一个知识库,以供后续问答时检索之用。我们借助 LangChain 框架来实现这一处理过程。

  • LangChain

    https://github.com/langchain-ai/langchainjs

首先是切分文本。虽然一张照片内的说明书内容有限,篇幅不会过长,但是为了更快、更精准地匹配问题内容,我们还是要把整段文本切开成一个个小块。

```javascript
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';const splitter = new RecursiveCharacterTextSplitter({chunkSize: 1000,chunkOverlap: 100,
});const docs = await splitter.splitDocuments(ocrText);
```

然后,我们把切分好的文本块进行向量化 (Embedding) 处理,并存到向量数据库中:

```javascript
import { OllamaEmbeddings } from '@langchain/community/embeddings/ollama';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';const embedder = new OllamaEmbeddings({model: 'gemma2’ // 使用本地模型
});const store = await MemoryVectorStore.fromDocuments(docs, embedder);
const retriever = store.asRetriever();
```

在上面的 Embedding 逻辑中,我们使用了本地模型。你需要提前安装并启动 Ollama,然后把一个模型下载到本地,如 ollama pull gemma2,就像拉取一个 npm 包一样简单。

  • Ollama

    https://ollama.com/

至此,我们就把用于检索的知识库准备好了,可以开门迎接用户的提问了。

ASR: 语音转文字

当用户用语音提问后,我们需要把音频内容转为文字,你可能在 HuggingFace 上看到过 ASR (Automatic Speech Recognition) 或者 STT (Speech to Text),指的都是这个转换过程。以下是核心逻辑:

```python
import torch
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline# 加载模型
model_id = "openai/whisper-base"
model = AutoModelForSpeechSeq2Seq.from_pretrained( model_id)
processor = AutoProcessor.from_pretrained(model_id)pipe = pipeline("automatic-speech-recognition",model=model,tokenizer=processor.tokenizer,feature_extractor=processor.feature_extractor,
)# 传入音频文件路径,生成文本
result = pipe(audio)
print('py_asr_res', result["text"])
```

得到用户问题的文本内容后,接下来就要进入到一个 LLM 应用的核心流程了。

RAG: 检索生成

在这个环节,我们要做的是拿用户的提问内容去之前准备好的向量知识库里做相似性匹配,再把检索到的相关文本块与问题一起传送给 LLM,LLM 会根据提示词生成回答。

首先是组织提示词模板。我们参考 LangChain Hub 中的提示词,编写模板:

  • LangChain Hub

    https://smith.langchain.com/

```javascript
import { ChatPromptTemplate } from '@langchain/core/prompts';const prompt = ChatPromptTemplate.fromMessages([['system', `你是一个问答任务助手。使用下面 context 中的检索上下文来回答问题。如果你不知道答案,就直接回答不知道。最多用三句话回答。`],['placeholder', '{context}'],['user', '{question}']
]);
```

接着,我们引入本地 LLM:

```javascript
import { ChatOllama } from '@langchain/community/chat_models/ollama';const model = new ChatOllama({model: 'gemma2',
});
```

由于 LLM 自有其特定的输出格式,我们还需要一个工具来把模型给出的回答解析成字符串:

```javascript
import { StringOutputParser } from '@langchain/core/output_parsers';const parser = new StringOutputParser();
```

最后,我们要用链条把 prompt、model、parser 串起来。什么?你说还没把问题和知识库做检索匹配?放心,LangChain 框架会帮我们处理这些,这正是「链条 (chain)」的奥义!

```javascript
import { RunnablePassthrough, RunnableSequence } from '@langchain/core/runnables';
import { formatDocumentsAsString } from 'langchain/util/document’;const ragChain = RunnableSequence.from([{question: new RunnablePassthrough(),context: retriever.pipe(formatDocumentsAsString), // retriever 就是此前生成的知识库},prompt,model,parser,
]);
```

我们只需要执行这个链条,就可以坐等 LLM 输出答案了:

```javascript
const output = await ragChain.invoke(userQuestionFromASR);
```

TTS: 文本转语音

现在,我们只需要把文本格式的回答内容给转成语音,然后播放给用户听即可:

```python
import ChatTTSchat = ChatTTS.Chat()if chat.load():pass
else:sys.exit(1)wavs = chat.infer(texts, use_decoder=True)# 保存音频为 .mp3 文件
for index, wav in enumerate(wavs):save_mp3_file(wav, index)
```

大功告成!!!

其他

我们使用了 Nuxt 搭建了这个 Web App 的前后端,上述的 OCR、ASR、TTS 都串联其中,非常方便!

  • Nuxt

    https://www.notion.so/https-bruno-simon-com-d63010e58be2449e84e54e0a4c557a40?pvs=21

GUI 方面,我们使用了 LangUI 这个 TailwindCSS 组件库,找到想用的组件,直接复制粘贴代码就行了,非常方便 +1!

  • LangUI

    https://github.com/LangbaseInc/langui

我和队友都是前端工程师,我们本着「应 JS 尽 JS」的信条,在作品中最大限度地用 Web 技术栈来实现功能。前端切图没在怕的,非常自豪!

规划和展望

「药童」这个作品,在 Gemma Hackathon 中得到了评委的认可,在故事性、创造性、实用性三个维度的综合评分名列前茅。这印证了我们的创意和理念确实有其价值。

在人工智能能力突飞猛进的今天,我们很容易就能感受到 AI 技术的强大力量,也都在积极乐观地畅想它将在各个领域掀起变革。然而在这样的狂欢氛围中,我们也可能很容易就忽略了那些身处热潮之外的群体,忽略了一点点巧妙的技术应用就能给他们带来帮助。技术可以在高空中绽放出绚烂夺目的光芒,也同样可以在细微处散发温热,暖人心窝。作为使用技术的人,我们开发者的目光要投向哪里,这至关重要。

以现实的眼光来审视,「药童」距离成为一个成熟产品,还有些技术性问题需要解决、优化,比如提升响应速度、支持多轮对话、固定音色、云端部署等等。我会发挥 Web 技术的灵活优势,「药童」可以是微信小程序、网页或任何形态,可以读药品说明书、家电说明书或任何文字内容,运用到任何需要它的地方。我会延续初心,尽我所能用技术提供帮助,哪怕用户群体再少、应用场景再窄。

写在最后

感谢 Jax 的创作分享,我们也期待「药童」能够为更多开发者提供灵感,激发更多有温度的创新体验。

如果您也想将自己的实践案例与更多开发者分享,欢迎报名参与谷歌开发者招募活动,积累资源和开发经验,收获灵感和惊喜,探索技术的无限可能!

8ab28bb8f7df6a9639e6dbfeb0070737.png

扫描二维码提交报名

和伙伴们一起探索 Google 技术


bf8954330c80795fa43a541fc1ce4513.gif 点击屏末  | 即刻报名谷歌开发者招募活动

2522cc45ee0e21a9311b47ef6c4cf22d.png

7f44af0ce87e54b31f7f4c621262ec1b.png

de0e2e308cdb4aab6a121dc034b33027.png

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

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

相关文章

详解Spring Bean的生命周期

详解Bean的生命周期 前言 在我们没有使用Spring框架之前,创建对象一般都是使用new关键字进行创建,当然除了new关键字外,还有 运用反射手段,使用Class类的newInstance方法 或者 Constructor类中的newInstance方法使用clone方法使…

JavaScript语法基础之DOM基础

目录 1. DOM 基础 1.1. DOM 是什么? 1.1.1. DOM 对象 1.1.2. DOM 结构 1.2. 节点类型 1.3. 获取元素 1.3.1. getElementById() 1.3.2. getElementsByTagName() 1.3.3. getElementsByClassName() 1.3.4. getElementsByName() 1.4.如何去操作对象 修改属性…

IP SSL证书的未来趋势:适应不断变化的安全挑战

随着网络攻击手段的不断进化和用户对隐私保护意识的增强,IP SSL证书作为保障网络安全的关键组件之一,也在不断地发展和完善。本文将探讨IP SSL证书的未来趋势,以及如何适应这些不断变化的安全挑战。 当前状况与挑战 网络安全意识提升&#…

ARM 裸机与 Linux 驱动对比及 Linux 内核入门

目录 ARM裸机代码和驱动的区别 Linux系统组成 内核五大功能 设备驱动分类 内核类型 驱动模块 驱动模块示例 Makefile配置 命令 编码辅助工具 内核中的打印函数 printk 函数 修改打印级别 ​编辑 打印级别含义 驱动多文件编译 示例 模块传递参数 命令行传递参数…

python-docx 实现 Word 办公自动化

前言:当我们需要批量生成一些合同文件或者简历等。如果手工处理对于我们来说不仅工作量巨大,而且难免会出现一些问题。这个时候运用python处理word实现自动生成文件可极大的提高工作效率。 python-docx是python的第三方插件,用来处理word文件…

Kubectl命令、初识pod、namespace

文章目录 一、Kubectl简介基础命令1.基本信息命令2.创建和更新资源命令3.删除资源命令4. 查看日志和调试命令5. 端口转发和复制文件命令6. 部署管理命令7. 伸缩命令8. 配置和上下文管理命令9.常用命令 二、Pod简介核心概念pod常见状态调度和初始化阶段容器创建和运行阶段异常状…

Qt网络通信——TCP和UDP

一、TCP通信 TCP通信必须先建立 TCP 连接,通信端分为客户端和服务器端。 Qt 为服务器端提供了 QTcpServer 类用于实现端口监听,QTcpSocket 类则用于服务器和客户端之间建立连接。大致流程如下图所示: 1. 服务器端建立 1.1 监听——listen() …

PPP简介

介绍PPP特性的定义和目的。 定义 PPP(Point-to-Point Protocol)协议是一种点到点链路层协议,主要用于在全双工的同异步链路上进行点到点的数据传输。 目的 PPP协议是在串行线IP协议SLIP(Serial Line Internet Protocol&#x…

代码随想录:动态规划6-10

62、不同路径 题目 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径…

史上最全的软件工厂考试简答题教程

软件工程考试简答题 1. 有人认为软件开发时,一个错误发现得越晚,为改正它所付出的代价越大。提出你的观点并解释原因? (1)在软件开发的不同阶段进行修改付出的代价是很不相同的,在早期引入变动&#xff0c…

openai whisper使用

whisper使用 介绍 Whisper是一种通用的语音识别模型。它是在大量不同音频数据集上训练的,也是一个多任务模型,可以执行多语言语音识别、语音翻译和语言识别。 GitHub:https://github.com/openai/whisper 论文链接:https://arx…

注册Github账号详细过程

目录 一、准备工作 二、注册步骤 一、准备工作 在注册GitHub账号之前,请确保您已经准备好以下信息: 一个有效的电子邮箱地址:用于接收验证邮件和GitHub的后续通知。 用户名:确保该用户名在GitHub上是唯一的,且符合…

turtle画图知识

Turtle库是Python编程语言中的一个库,用于创建各种类型的图形,包括简单圆形、线条、路径和图片。它支持多种图形类型,并且可以绘制出各种复杂的形状。 以下是一些基本的使用方法: 1. 创建一个新的Turtle对象: pytho…

Leetcode JAVA刷刷站(53)最大子数组和

一、题目概述 二、思路方向 这个问题是一个经典的算法问题,称为“最大子序和”(Maximum Subarray Problem)。解决这个问题的一个高效方法是使用“Kadanes Algorithm”,它只需要遍历数组一次,就能在 O(n) 时间复杂度内…

CVPR2023《DNF: Decouple and Feedback Network for Seeing in the Dark》暗光图像增强论文阅读笔记

相关链接 论文链接 https://openaccess.thecvf.com/content/CVPR2023/papers/Jin_DNF_Decouple_and_Feedback_Network_for_Seeing_in_the_Dark_CVPR_2023_paper.pdf 代码链接 https://github.com/Srameo/DNF 摘要 RAW数据的独特属性在低光照图像增强方面展现出巨大潜力。…

C语言典型例题47

《C程序设计教程(第四版)——谭浩强》 习题3.7 输入4个整数,要求按照从小到大的顺序输出 4个数之间进行比较,冒泡排序最最最详细过程,如果想更改为任意数之间相互比较,只需要修改两个地方(数组大…

力扣面试经典算法150题:买卖股票的最佳时机 II

买卖股票的最佳时机 II 今天的题目是力扣面试经典150题中的数组的中等难度题:买卖股票的最佳时机 II。 题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/?envTypestudy-plan-v2&envIdtop-interview-150 问…

教程:postman的平替hoppscotch,又叫postwoman,hoppscotch的docker-compose安装过程

目录 1. 背景2. 前期准备2.1 准备docker-compose文件,两个版本,一个3合1,一个分开2.1.1 3合1版本(推荐)2.1.2 独立版本 2.2 准备安装nginx-proxy-manager(可选)2.2 准备.env文件2.2.1 默认ip的.…

Spring Boot OAuth2.0应用

本文展示Spring Boot中,新版本OAuth2.0的简单实现,版本信息: spring-boot 2.7.10 spring-security-oauth2-authorization-server 0.4.0 spring-security-oauth2-client 5.7.7 spring-boot-starter-oauth2-resource-server 2.7.10展示三个服务…

Android高版本抓包总结

方案1 CharlesVirtualXposedJustTrustMe 推荐使用三星手机此方案 VirtualXposed下载链接:https://github.com/android-hacker/VirtualXposed/releases JustTrustMe下载链接:https://github.com/Fuzion24/JustTrustMe/releases/ 下载完成后使用adb命令…