从想法到现实:如何构建自己的个人 AI 助理 Web 应用程序。是否希望拥有一个像托尼·斯塔克饰演的贾维斯那样的个人人工智能助理?或者《钢铁侠星期五》来帮助完成任务、回答问题并陪伴在身边?
很庆幸生活在这个时代,本文将把这个科幻梦想变成了现实!算是很少的一部分,一个雏形。在本文中,将展示如何使用 Python FastAPI、ReactJS 和 GPT-3 语言模型构建自己的 AI 助手。
将看到人工智能助手的演示,并探索系统设计和架构。将详细介绍后端和前端的工作原理,以便更好地了解幕后所发生的一切。
从想法到实现:将梦幻般的人工智能助手变成有形的网络应用程序!在之前的文章《掌握AI摘要技术解锁个人第二大脑》中,探索了如何使用 Python 和 ChatGPT 创建人工智能驱动的第二大脑。第二个大脑能够根据用户提供的上下文数据来记住和组织信息。
在这篇文章中,通过实际构建一个个人人工智能助理来将事情提升到一个新的水平,可以用自然语言与它交谈、倾听和提问。
此外,借助 GPT-3 和网络抓取的强大功能,该人工智能助手可以提供超出用户提供的上下文数据的更多见解和答案。
人工智能助手的交互方式
先来看下这个简单版本的 JARVIS 所涉及的步骤:
- 将鼠标悬停在
说些什么
按钮上 - 录音开始
- 对着麦克风说出你的问题
- 将鼠标光标移离按钮
- 后端魔法奇迹发生了!
- 人工智能助手通过扬声器向你说出答案
- 还可以在用户界面中获得问题/答案的文本记录
系统设计和架构一览
从这里开始将注意力转移到技术细节上。将系统分解为多个组件,它会是这样的:
- GPT-3 作为大型语言模型 (LLM)
- Llama-Index 用于向量化上下文数据并将其传递给 GPT-3
- Python FastAPI 服务器与经过训练的 LLM 模型进行交互
- ReactJS 和 ChakraUI 构建前端 UI
- 用于语音输入的 Webkit SpeechRecognition 库
- 用于文本转语音的 Webkit SpeechSynthesisUtterance 库
如果把所有这些放在一起,系统就是这样的。
从左到右、从上到下阅读系统设计图。
现在对系统的工作原理有了更全面的了解,接下来将按照前端和后端实现逐步深入的介绍。
后端:为 AI 助手提供支持
在过去的几个月里,ChatGPT 毫不夸张地说已经占领了世界。可以要求它做作业、准备演示文稿、编写 SQL 查询、编写代码、书写商务邮件、生成逼真的图像和视频等等。
尽管它可以做所有这些不同的事情,但当问它有关生活的问题时,它仍然会很挣扎。如你昨天吃了什么?上周你见到了谁?你的咖啡买了吗?
ChatGPT 无法回答这些问题,因为它无法了解你的个人生活。需要向其提供个人数据,它才能提供帮助。这就是以下内容的用武之地:
- 包含日记条目的文本文件
- Llama Index 用于读取此文本文件、矢量化数据并将其作为上下文传递给 GPT-3
这两者的结合使 GPT-3 能够回答对个人生活的任何问题。
首先,需要日志中存在数据,GPT-3 才能提供帮助。
第一步是根据这些数据训练 GPT-3 模型。接下来,将经过训练的模型保存在服务器上。
from llama_index import GPTSimpleVectorIndex, SimpleDirectoryReader # Load data from the journal text file documents = SimpleDirectoryReader("./data").load_data() # Create a simple vector index index = GPTSimpleVectorIndex(documents) index.save_to_disk("generated_index.json") # Create an infinite loop asking for user input and then breaking out of the loop when the response is empty while True: query = input("Ask a question: ") if not query: print("Goodbye") break # query the index with the question and print the result result = index.query(query) print(result)
现在,构建一个非常简单的 FastAPI 端点来与这个保存的模型进行交互。端点逻辑很简单:
- 传递来自WEB应用程序的用户问题
- 向保存的 GPT-3 模型提问
- 以 JSON 格式将答案返回给客户端
from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from llama_index import GPTSimpleVectorIndex app = FastAPI() # Define allowed origins origins = [ "http://localhost:3000", "http://localhost:5000", "http://localhost:8000", "http://localhost:8080", ] # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/answers") async def get_answer(question: str): index = GPTSimpleVectorIndex.load_from_disk("generated_index.json") answer = index.query(question) return {"answer": answer.response}
此后,由前端负责将数据呈现给用户。
前端:将 AI 助手带入生活
用户与WEB应用程序交互,基本上有 4 个任务:
- 通过麦克风将用户的问题转化为文字
- 通过 API 调用将问题传递给服务器
- 将来自服务器的答案从文本转换为语音,并通过用户的扬声器产生输出
- 在进行语音转文本和文本转语音时向用户显示文字记录
import React, { useState, useEffect } from "react"; import { Button, VStack, Center, Heading, Box, Text } from "@chakra-ui/react"; function App() { const [transcript, setTranscript] = useState(""); const [answer, setAnswer] = useState(""); const [isRecording, setIsRecording] = useState(false); const [buttonText, setButtonText] = useState("Say Something"); const [recognitionInstance, setRecognitionInstance] = useState(null); useEffect(() => { const recognition = new window.webkitSpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; recognition.lang = "en-US"; recognition.onresult = (event) => { let interimTranscript = ""; let finalTranscript = ""; for (let i = event.resultIndex; i < event.results.length; i++) { const transcript = event.results[i][0].transcript; if (event.results[i].isFinal) { finalTranscript += transcript + " "; } else { interimTranscript += transcript; } } setTranscript(finalTranscript); }; setRecognitionInstance(recognition); }, []); const recordAudio = () => { setAnswer(""); setButtonText("Recording..."); setIsRecording(!isRecording); recognitionInstance.start(); }; const stopAudio = async () => { setButtonText("Say Something"); setIsRecording(!isRecording); recognitionInstance.stop(); const response = await fetch( `http://127.0.0.1:8000/answers?question=${transcript}` ); const data = await response.json(); setAnswer(data["answer"]); const utterance = new SpeechSynthesisUtterance(data["answer"]); window.speechSynthesis.speak(utterance); }; return ( <Box bg="black" h="100vh" display="flex" justifyContent="center" alignItems="center" padding="20px" > <Center> <VStack spacing={12}> <Heading color="red.500" fontSize="8xl"> 👋 I am your personal assistant 🤖 </Heading> <Button colorScheme="red" width="300px" height="150px" onMouseOver={recordAudio} onMouseLeave={stopAudio} fontSize="3xl" > {buttonText} </Button> {transcript && ( <Text color="whiteAlpha.500" fontSize="2xl"> Question: {transcript} </Text> )} {answer && ( <Text color="white" fontSize="3xl"> <b>Answer:</b> {answer} </Text> )} </VStack> </Center> </Box> ); } export default App;
关于语音部分,也可以借助AI来实现不同的声音,这里就不展开了。