nodejs 调用智谱ai
封装 ZhipuSdk 类
为了方便地调用智谱 AI 的接口,我们首先封装一个 ZhipuSDK 类。这个类将初始化 HTTP 客户端,并提供创建补全功能的方法。
import axios from "axios";
export class ZhipuSDK {
/**
* 构造函数
* 初始化HTTP客户端,用于与API服务器进行通信
* @param {Object} options - 包含API密钥的配置对象
*/
constructor(options) {
this.client = axios.create({
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${options.apiKey}`,
},
baseURL: "https://open.bigmodel.cn/api/paas/v4",
// 启用跨域请求中的凭证携带
withCredentials: true,
});
}
/**
* 异步创建补全功能
*
* 本函数通过POST请求与服务器通信,以生成基于给定消息的补全响应
* 它支持流式处理,可以通过回调函数实时处理生成的数据
*
* @param {Object} options - 包含补全请求配置的选项对象
* @param {Object} handlers - 包含处理生成数据的回调函数的对象,默认为空对象
* @returns {Promise<Object>} - 返回一个Promise,解析为补全响应数据
*/
async createCompletions(options, handlers = {}) {
try {
// 清理消息历史,移除空消息和错误消息
const cleanedMessages = options.messages.filter(
(msg) =>
msg.content &&
msg.content.trim() !== "" &&
!msg.content.includes("An error occurred")
);
// 发起请求
const response = await this.client({
method: "POST",
url: "/chat/completions",
responseType: options.stream ? "stream" : "json",
data: {
model: options.model,
messages: options.messages,
stream: !!options.stream,
},
});
// 如果不是流式处理,直接返回响应数据
if (!options.stream) {
handlers.onProgress?.(response.data);
return response.data;
}
// 初始化处理流式响应的变量
let unhandledMessage = "";
let deltaContent = "";
let lastResponse;
// 处理流式响应数据
for await (const chunk of response.data) {
const messages = (unhandledMessage + chunk.toString()).split("\n");
unhandledMessage = "";
for (const message of messages) {
if (!message.startsWith("data:")) {
unhandledMessage += message;
continue;
}
if (message === "data: [DONE]") {
handlers.onProgressEnd?.(lastResponse);
continue;
}
try {
if (!message.endsWith("}")) {
unhandledMessage += message;
continue;
}
const json = JSON.parse(message.replace("data: ", ""));
if (options.stream === "append") {
deltaContent += json.choices[0].delta.content;
json.choices[0].message = deltaContent;
}
lastResponse = json;
handlers.onProgress?.(json);
} catch (error) {
unhandledMessage += message;
}
}
}
return lastResponse;
} catch (error) {
console.error("ZhipuSDK Error:", error.response?.data || error.message);
throw error;
}
}
}
创建 API 接口
接下来,我们创建一个 API 接口,用于接收客户端发送的消息,并调用 ZhipuSDK 类的 createCompletions 方法来生成补全响应。
router.post("/chat-zhipu", async (req, res) => {
const { messages } = req.body;
if (!messages?.length) {
return res.status(400).json({ error: "Messages are required" });
}
try {
// 设置SSE响应头
setupSSE(res);
const ai = new ZhipuSDK({
apiKey: process.env.ZHIPU_API_KEY,
});
await ai.createCompletions(
{
model: "glm-4",
messages: messages,
stream: true,
},
{
onProgress: (response) => {
const { content } = response.choices[0].delta;
if (content) {
res.write(`data: ${JSON.stringify({
type: "message",
content
})}\n\n`);
}
},
onProgressEnd: () => {
res.end();
}
}
);
} catch (error) {
console.error("Chat error:", error.response?.data || error);
res.write(`data: ${JSON.stringify({
type: "error",
content: "An error occurred while processing your request."
})}\n\n`);
res.end();
}
});
注意事项
API 密钥:在使用智谱 AI 的接口之前,需要先获取 API 密钥,并将其设置为环境变量 ZHIPU_API_KEY。
URL 的正确性:请确保 baseURL 的值是正确的。如果遇到网络问题或无法解析该 URL,可能需要检查 URL 的合法性,并适当重试。
错误处理:在调用接口时,要妥善处理可能出现的错误,例如网络请求失败、API 限制等。通过捕获异常并返回相应的错误信息,可以提高应用的健壮性。