尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Node.js环境调用水墨江南模型API实战教程

Node.js环境调用水墨江南模型API实战教程 Node.js环境调用水墨江南模型API实战教程最近在做一个国风主题的创意项目需要批量生成一些带有古典韵味的文案和配图。手动创作效率太低于是把目光投向了AI。水墨江南模型在国风内容生成上口碑不错但官方文档对Node.js环境的调用示例讲得比较简略。摸索了一阵子总算把整个流程跑通了从环境搭建到错误处理都踩了一遍坑。今天就把这套在Node.js里调用水墨江南模型API的实战方法分享出来不管你是用Express还是Koa都能快速集成。我会手把手带你走一遍从安装依赖开始到写出一个健壮的、能处理流式响应的国风文案生成接口。如果你也喜欢折腾这些跟着做一遍半小时内就能让模型跑起来。1. 准备工作环境与依赖开始之前你得有个能跑Node.js的环境。我假设你已经装好了Node.js和npm或者yarn、pnpm都行。打开终端输入node -v和npm -v检查一下版本别太老就行建议Node.js版本在16以上。接下来我们创建一个新的项目目录。找个你喜欢的地方打开命令行mkdir ink-jiangnan-api-demo cd ink-jiangnan-api-demo npm init -y这行命令会生成一个package.json文件记录项目信息和依赖。调用API我们需要一个HTTP客户端库。社区里常用的有axios和node-fetch。axios功能更全拦截器、自动转换JSON这些用起来方便node-fetch更轻量API设计接近浏览器的Fetch。这个教程里我两个都会提你可以按喜好选。另外如果我们用Express框架来构建API服务也需要安装它。安装依赖这里我把两个HTTP客户端都装上实际用哪个选哪个npm install axios node-fetch express如果你打算用Koa可以安装koa和koa-routernpm install koa koa-router axios node-fetch装好之后你的package.json的dependencies里应该能看到它们。准备工作就绪我们可以进入正题了。2. 获取并配置API密钥要调用水墨江南模型的API你得先有把“钥匙”——也就是API Key。通常你需要去模型的官方平台注册账号然后在控制台创建一个应用或项目就能拿到专属的密钥。拿到密钥后千万别直接硬编码在代码里特别是如果你打算把代码上传到GitHub等公共平台。最好的做法是使用环境变量。在项目根目录下创建一个.env文件touch .env然后用编辑器打开这个.env文件把你的API密钥放进去INK_JIANGNAN_API_KEY你的_实际_API_密钥_在这里 INK_JIANGNAN_BASE_URLhttps://api.example.com/v1 # 替换为实际的API基础地址注意把你的_实际_API_密钥_在这里和https://api.example.com/v1换成你从平台获取的真实信息。.env文件通常包含敏感信息记得把它加入到.gitignore文件中避免误提交。在Node.js代码中我们可以使用dotenv包来读取这个文件。先安装它npm install dotenv然后在你的项目入口文件比如app.js或index.js的最顶部添加这行代码require(dotenv).config();这样你就可以通过process.env.INK_JIANGNAN_API_KEY来安全地访问密钥了。3. 编写核心API调用函数有了密钥我们就可以构造请求了。水墨江南模型的API通常是RESTful风格的我们需要设置正确的请求头特别是认证头和请求体。3.1 使用axios发起请求先来看看用axios怎么实现。创建一个名为apiClient.js的文件const axios require(axios); require(dotenv).config(); // 创建axios实例统一配置 const inkJiangnanClient axios.create({ baseURL: process.env.INK_JIANGNAN_BASE_URL, timeout: 30000, // 30秒超时 headers: { Content-Type: application/json, Authorization: Bearer ${process.env.INK_JIANGNAN_API_KEY} } }); /** * 调用水墨江南文本生成API * param {string} prompt - 生成提示词 * param {object} options - 其他参数如模型版本、生成长度等 * returns {Promiseobject} - API响应数据 */ async function generateTextWithAxios(prompt, options {}) { const defaultOptions { model: ink-jiangnan-latest, // 指定模型版本请根据实际情况调整 max_tokens: 500, temperature: 0.7, stream: false // 是否为流式响应先设为false }; const requestData { ...defaultOptions, ...options, prompt: prompt }; try { console.log(正在请求生成文本提示词: ${prompt.substring(0, 50)}...); const response await inkJiangnanClient.post(/chat/completions, requestData); // 端点路径请根据实际API调整 console.log(文本生成请求成功); return response.data; } catch (error) { console.error(调用文本生成API失败:, error.message); if (error.response) { // 请求已发出服务器返回了错误状态码 console.error(错误状态码:, error.response.status); console.error(错误响应体:, error.response.data); } else if (error.request) { // 请求已发出但没有收到响应 console.error(未收到服务器响应请检查网络或API地址); } // 向上抛出错误由调用方处理 throw new Error(API调用失败: ${error.message}); } } module.exports { generateTextWithAxios };这个函数做了几件事合并默认参数和用户传入的参数设置认证头用POST方法发送请求并提供了基本的错误处理。3.2 使用node-fetch发起请求如果你更喜欢node-fetch可以这样写。在同一个apiClient.js文件里追加一个函数或者新建一个文件const fetch require(node-fetch); require(dotenv).config(); /** * 调用水墨江南文本生成API (使用node-fetch) * param {string} prompt - 生成提示词 * param {object} options - 其他参数 * returns {Promiseobject} - API响应数据 */ async function generateTextWithFetch(prompt, options {}) { const defaultOptions { model: ink-jiangnan-latest, max_tokens: 500, temperature: 0.7, stream: false }; const requestData { ...defaultOptions, ...options, prompt: prompt }; const apiUrl ${process.env.INK_JIANGNAN_BASE_URL}/chat/completions; try { console.log(正在请求生成文本提示词: ${prompt.substring(0, 50)}...); const response await fetch(apiUrl, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${process.env.INK_JIANGNAN_API_KEY} }, body: JSON.stringify(requestData) }); if (!response.ok) { const errorText await response.text(); throw new Error(HTTP ${response.status}: ${errorText}); } const data await response.json(); console.log(文本生成请求成功); return data; } catch (error) { console.error(调用文本生成API失败:, error.message); throw new Error(API调用失败: ${error.message}); } } // 将新函数也导出 module.exports { generateTextWithAxios, generateTextWithFetch };两种方式都能用axios的错误处理更自动一些node-fetch更接近原生。你可以根据项目习惯选择。4. 处理流式响应很多AI模型的API支持流式响应stream: true数据是一段一段传回来的而不是等全部生成完再一次性返回。这对于生成较长内容时提升用户体验很有帮助用户可以边生成边看到结果。处理流式响应稍微复杂点因为我们需要监听数据流。这里以axios为例因为它对流式响应的支持比较友好需要设置responseType: stream。我们在apiClient.js里再添加一个处理流式响应的函数const { Transform } require(stream); /** * 流式调用水墨江南文本生成API * param {string} prompt - 生成提示词 * param {object} options - 其他参数 * param {function} onDataChunk - 收到数据块时的回调函数 (chunk: string) void * returns {Promisestring} - 最终生成的完整文本 */ async function generateTextStreamWithAxios(prompt, options {}, onDataChunk) { const requestData { model: ink-jiangnan-latest, max_tokens: 500, temperature: 0.7, stream: true, // 关键开启流式 ...options, prompt: prompt }; try { console.log(开始流式生成文本提示词: ${prompt.substring(0, 50)}...); const response await inkJiangnanClient.post(/chat/completions, requestData, { responseType: stream // 告诉axios我们期待一个流 }); let fullContent ; // 创建一个转换流来解析SSE (Server-Sent Events) 格式 const transformStream new Transform({ decodeStrings: false, transform(chunk, encoding, callback) { // 数据可能以多个事件的形式一起到达先按换行分割 const lines chunk.toString().split(\n); for (const line of lines) { if (line.startsWith(data: )) { const dataStr line.substring(6); // 去掉 data: 前缀 if (dataStr [DONE]) { // 流结束标志 console.log(流式生成结束。); } else { try { const parsed JSON.parse(dataStr); // 假设响应结构里 choices[0].delta.content 是增量内容 const contentChunk parsed.choices?.[0]?.delta?.content || ; if (contentChunk) { fullContent contentChunk; // 如果提供了回调则调用它 if (typeof onDataChunk function) { onDataChunk(contentChunk); } } } catch (e) { // 忽略非JSON行或解析错误 } } } } callback(); } }); // 返回一个Promise当流结束时解析 return new Promise((resolve, reject) { response.data.pipe(transformStream); response.data.on(end, () { console.log(数据流接收完毕。); resolve(fullContent); }); response.data.on(error, (err) { console.error(接收流数据时出错:, err); reject(err); }); }); } catch (error) { console.error(流式请求失败:, error.message); throw error; } }这个函数看起来有点长但核心逻辑是发起一个流式请求然后监听返回的数据流按行解析提取出每一块生成的文本并拼接起来。我们还提供了一个onDataChunk回调这样调用方可以实时拿到每一块文本比如实时推送到网页前端。别忘了把这个新函数也加入到module.exports里。5. 构建一个完整的Express API服务现在我们把上面的功能集成到一个实际的Web服务里。创建一个server.js文件用Express搭建一个简单的HTTP服务器提供一个生成国风文案的接口。const express require(express); const { generateTextWithAxios, generateTextStreamWithAxios } require(./apiClient); require(dotenv).config(); const app express(); const PORT process.env.PORT || 3000; // 中间件解析JSON请求体 app.use(express.json()); // 健康检查端点 app.get(/, (req, res) { res.json({ status: ok, message: 水墨江南模型API服务运行中 }); }); // 1. 普通文本生成接口 (一次性返回) app.post(/api/generate, async (req, res) { try { const { prompt, ...options } req.body; if (!prompt || prompt.trim() ) { return res.status(400).json({ error: 提示词(prompt)不能为空 }); } console.log(收到生成请求提示词: ${prompt}); const result await generateTextWithAxios(prompt, options); // 假设API返回结构中有 choices[0].message.content const generatedText result.choices?.[0]?.message?.content || result.content || 未生成内容; res.json({ success: true, data: { prompt: prompt, generated_text: generatedText, full_response: result // 可选返回完整响应用于调试 } }); } catch (error) { console.error(处理生成请求时出错:, error); res.status(500).json({ success: false, error: 生成失败, details: error.message }); } }); // 2. 流式文本生成接口 (Server-Sent Events) app.post(/api/generate-stream, async (req, res) { // 设置SSE相关的响应头 res.setHeader(Content-Type, text/event-stream); res.setHeader(Cache-Control, no-cache); res.setHeader(Connection, keep-alive); res.flushHeaders(); // 立即发送头部建立连接 const { prompt, ...options } req.body; if (!prompt || prompt.trim() ) { // 对于SSE我们需要以事件形式发送错误 res.write(event: error\ndata: ${JSON.stringify({ error: 提示词(prompt)不能为空 })}\n\n); res.end(); return; } console.log(收到流式生成请求提示词: ${prompt}); try { await generateTextStreamWithAxios( prompt, options, (chunk) { // 每收到一个数据块就通过SSE发送给客户端 res.write(data: ${JSON.stringify({ chunk })}\n\n); } ); // 发送结束标志 res.write(event: done\ndata: {}\n\n); } catch (error) { console.error(流式生成过程中出错:, error); res.write(event: error\ndata: ${JSON.stringify({ error: error.message })}\n\n); } finally { res.end(); } }); // 启动服务器 app.listen(PORT, () { console.log(服务器启动监听端口: ${PORT}); console.log(普通生成接口: http://localhost:${PORT}/api/generate); console.log(流式生成接口: http://localhost:${PORT}/api/generate-stream); });这个服务提供了两个端点POST /api/generate: 传统的请求-响应模式等模型全部生成完后一次性返回结果。POST /api/generate-stream: 流式接口使用Server-Sent Events (SSE) 技术生成一点就推送一点到客户端适合需要实时显示生成过程的场景。你可以用Postman、curl或者写个简单的前端页面来测试这些接口。6. 错误处理与重试机制网络请求总有可能失败可能是网络波动也可能是API服务暂时过载。一个健壮的程序需要有错误处理和重试机制。我们可以写一个简单的包装函数在请求失败时自动重试几次。在apiClient.js里添加这个工具函数/** * 带重试机制的请求包装器 * param {Function} requestFn - 返回Promise的请求函数 * param {number} maxRetries - 最大重试次数 (默认3次) * param {number} baseDelay - 基础延迟毫秒数 (默认1000ms会指数退避) * returns {Promiseany} - 请求结果 */ async function retryRequest(requestFn, maxRetries 3, baseDelay 1000) { let lastError; for (let attempt 1; attempt maxRetries; attempt) { try { return await requestFn(); } catch (error) { lastError error; console.warn(请求失败第${attempt}次重试。错误: ${error.message}); if (attempt maxRetries) { break; // 最后一次重试也失败了不再等待 } // 指数退避延迟时间逐渐增加 const delay baseDelay * Math.pow(2, attempt - 1); console.log(等待 ${delay}ms 后重试...); await new Promise(resolve setTimeout(resolve, delay)); } } // 所有重试都失败了 throw new Error(请求失败已重试${maxRetries}次。最后错误: ${lastError.message}); }然后修改我们之前的generateTextWithAxios函数让它支持重试async function generateTextWithAxiosRetry(prompt, options {}, maxRetries 3) { const requestFn () generateTextWithAxios(prompt, options); // 注意这里调用的是之前写的、不带重试的版本 return retryRequest(requestFn, maxRetries); }这样当遇到网络错误或者API返回5xx状态码时程序会自动重试增加了可靠性。对于流式请求重试逻辑会更复杂一些因为涉及中断和重新建立流这里就不展开了但思路类似。7. 总结走完这一趟你应该能在自己的Node.js项目里轻松调用水墨江南模型的API了。整个过程从环境配置、依赖安装开始到编写核心的请求函数再到处理更高级的流式响应最后集成进一个Web服务并加上错误重试。实际用起来有几个小地方可以再优化。比如把API密钥和配置管理得更规范一些可以考虑用专业的配置管理库。对于高并发场景可能需要加入请求队列或者限流避免触发API的速率限制。日志记录也可以做得更细致方便排查问题。代码里我留了一些注释比如API的端点路径 (/chat/completions) 和响应结构 (choices[0].delta.content)这些需要你根据水墨江南模型API的实际文档进行调整。每个平台的API设计可能略有不同。总的来说这套方法算是提供了一个扎实的起点。你可以基于这个框架去探索模型更多的功能比如图像生成、风格调整等等。希望这篇教程能帮你省点摸索的时间快速把想法实现出来。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
返回列表