实现一个简单的聊天应用,用户可以通过输入问题或点击"Surprise me"按钮获取随机问题,并从后端API获取回答。
javascript
import { useState } from "react";
function App() {
const [ value, setValue] = useState(""); // 存储用户输入的问题。
const [error, setError] = useState(""); // 存储错误信息。
const [chatHistory, setChatHistory] = useState([]); // 存储聊天记录,格式为一个数组,每个元素是一个包含 role(用户或模型)和 parts(消息内容)的对象。
const surpriseOptions = [
'Who won the latest Nobel Peace Prize?',
'Where does pizza come from?',
'Who do you make a sandwich?'
] // 一个包含随机问题的数组
const surprise = () => {
const randomValue = surpriseOptions[Math.floor(Math.random() * surpriseOptions.length)];
setValue(randomValue);
} // 从 surpriseOptions 中随机选择一个问题,并将其设置为 value
// getResponse 是一个异步函数,用于向后端API发送请求并获取回答
const getResponse = async () => {
if (!value){
setError("Please enter a question");
return;
} // 如果 value 为空,设置错误信息并返回。
try {
const options = {
method: 'POST',
body: JSON.stringify({
history: chatHistory,
message: value
}), // 转换为 JSON 字符串
headers: {
'Content-Type': 'application/json'
}
}
const response = await fetch('http://localhost:8000/gemini', options); // 使用 fetch 发送POST请求,请求体包含 chatHistory 和用户输入的 value
const data = await response.text();
console.log(data);
setChatHistory(oldChatHistory => [...oldChatHistory, {
role: "user",
parts: [{text: value}],
},
{
role: "model",
parts: [{text: data}],
}
]) // 将API返回的回答添加到 chatHistory 中
setValue("") // 清空输入框
}
catch (error) {
console.error(error);
setError("Something went wrong! Please try again later.");
} // 如果发生错误,设置错误信息
}
const clear = () => {
setValue("")
setError("")
setChatHistory([])
} // 清空输入框、错误信息和聊天记录。
return (
<div className="app">
<p>
What do you want to know?
<button className="surprise" onClick={surprise} disabled={!chatHistory}>Surprise me</button>
</p>
<!-- 如果 disabled 为 true,按钮不可点击;如果 disabled 为 false,按钮可点击。
如果 chatHistory 为空([]),它仍然是一个对象,而所有对象在布尔上下文中都被视为 true,!chatHistory 返回 false。
-->
<div className="input-container">
<input
value={value}
placeholder="When is Christmas...?"
onChange={(e) => setValue(e.target.value)}
/>
<!-- e.target.value 用于获取事件目标(通常是输入框、下拉框等表单元素)的当前值。它通常与 onChange 事件一起使用,以便在用户输入时实时获取输入内容。 -->
{!error && <button onClick={getResponse}>Ask me</button>}
{error && <button onClick={clear}>Clear</button>}
</div>
{error && <p>{error}</p>}
<div className="search-result">
{chatHistory.map((chatItem, _index) => <div key={_index}>
<p className="answer">{chatItem.role}: {chatItem.parts.map(part => part.text).join(" ")}</p>
</div>)}
</div>
</div>
);
}
export default App;
渲染一个包含以下内容的界面:
- 一个标题和"Surprise me"按钮(仅在 chatHistory 不为空时可用)。
- 一个输入框和"Ask me"按钮(如果无错误)或"Clear"按钮(如果有错误)。
- 错误信息(如果有)。
- 聊天记录,每条记录显示用户问题和模型回答。
实现一个基于 Express 的 Node.js 服务器,用于与 Google 的 Generative AI 模型(Gemini)进行交互
javascript
const PORT = 8000
const express = require('express') // Node.js 的 Web 框架,用于构建服务器。
const cors = require('cors') // 用于处理跨域资源共享(CORS),允许前端与后端跨域通信。
const app = express()
app.use(cors()) // 启用 CORS 中间件,允许跨域请求。
app.use(express.json()) // 启用 JSON 解析中间件,以便服务器可以解析请求体中的 JSON 数据。
require('dotenv').config()
const { GoogleGenerativeAI } = require('@google/generative-ai') // Google 提供的 Generative AI SDK,用于与 Gemini 模型交互。
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_GEN_AI_KEY)
// 定义一个 POST 路由 /gemini,用于接收前端发送的请求。
app.post('/gemini', async (req, res) => {
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
// 使用聊天历史记录初始化一个 Gemini 聊天会话。
const chat = model.startChat({
history: req.body.history
}) // 从请求体中获取聊天历史记录。
const msg = req.body.message // 从请求体中获取用户发送的消息。
const result = await chat.sendMessage(msg) // 向 Gemini 模型发送用户的消息。
const response = await result.response
const text = response.text()
res.send(text) // 将模型的响应文本发送回前端。
}
)
// 启动服务器,监听指定的端口(PORT)。
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))