春联生成模型-中文-base与Node.js全栈开发快速构建节日应用春节将至想给你的网站或应用增添一点节日气氛吗或者你正在寻找一个有趣又实用的项目来练手全栈开发今天我们就来聊聊如何用Node.js和Express快速搭建一个能自动生成春联的Web应用。整个过程不复杂即使你刚接触Node.js不久跟着步骤走也能轻松搞定。这个应用的核心是集成一个专门生成中文春联的AI模型。我们不需要自己训练模型而是通过调用现成的模型服务API让后端Node.js应用去请求然后把生成的、充满节日祝福的春联漂亮地展示在前端页面上。从环境搭建到页面渲染我们将一步步走完一个典型全栈应用的开发流程。你会发现用Node.js构建这样的趣味应用既高效又有成就感。1. 从零开始搭建你的Node.js开发环境工欲善其事必先利其器。在写代码之前我们得先把“战场”布置好。对于Node.js开发来说环境配置非常简单。1.1 安装Node.js和npmNode.js是运行JavaScript的服务器环境而npmNode Package Manager是随Node.js一同安装的包管理工具我们之后安装各种依赖库全靠它。首先访问Node.js官方网站的下载页面。你会看到两个版本LTS长期支持版和Current最新特性版。对于学习和生产环境我强烈建议选择LTS版本它更稳定兼容性更好。下载对应你操作系统Windows、macOS或Linux的安装程序然后像安装普通软件一样运行它。安装过程中基本保持默认选项即可确保“Add to PATH”这一项是被勾选的这样你才能在命令行里直接使用node和npm命令。安装完成后我们来验证一下。打开你的终端Windows上是CMD或PowerShellmacOS/Linux上是Terminal输入以下两个命令node -v npm -v如果安装成功命令行会分别显示Node.js和npm的版本号比如v18.17.0和9.6.7。看到版本号就说明你的环境已经准备就绪了。1.2 初始化你的项目环境好了接下来创建一个专属的项目目录。在终端里导航到你习惯存放代码的文件夹然后执行mkdir spring-festival-app cd spring-festival-app现在我们在这个空文件夹里初始化一个新的Node.js项目npm init -y这个命令会快速生成一个package.json文件它是你项目的“身份证”和“说明书”里面记录了项目名称、版本、描述以及最重要的——项目依赖。-y参数表示接受所有默认选项省去了一路回车确认的麻烦。2. 构建应用骨架Express框架与基础结构有了项目基础我们开始搭建应用的“骨架”。这里我们选择Express它是Node.js生态里最流行、最轻量的Web应用框架能极大简化HTTP服务器、路由等功能的开发。2.1 安装核心依赖在项目根目录下运行以下命令来安装Expressnpm install express安装完成后你会看到项目里多了一个node_modules文件夹存放所有安装的库和package-lock.json文件锁定依赖版本确保一致性。为了让开发更便捷我们还需要一个工具nodemon。它能监听文件变化自动重启Node.js应用这样我们每次修改代码后就不用手动重启服务器了。我们把它作为“开发依赖”安装npm install --save-dev nodemon2.2 创建应用入口文件接下来在项目根目录创建一个名为app.js的文件这将是我们的主应用文件。打开app.js写入以下基础代码// 导入express框架 const express require(express); // 创建一个Express应用实例 const app express(); // 定义服务器监听的端口号优先使用环境变量PORT没有则用3000 const PORT process.env.PORT || 3000; // 设置模板引擎这里先用简单的HTML稍后解释 app.engine(html, require(ejs).renderFile); app.set(view engine, html); // 设置静态文件目录这样浏览器才能访问到CSS、JS、图片等文件 app.use(express.static(public)); // 定义一个最简单的路由当用户访问网站根路径时 app.get(/, (req, res) { // 先返回一个简单的文本响应测试服务器是否工作 res.send(春节快乐Node.js服务器运行正常。); }); // 启动服务器开始监听指定端口 app.listen(PORT, () { console.log(春联生成应用正在运行http://localhost:${PORT}); });现在让我们修改package.json文件添加一个启动脚本方便我们用nodemon来运行应用。找到package.json里的scripts部分修改或添加如下内容scripts: { start: node app.js, dev: nodemon app.js }回到终端运行npm run dev。如果看到“春联生成应用正在运行http://localhost:3000”的提示就说明成功了。打开浏览器访问http://localhost:3000你应该能看到“春节快乐Node.js服务器运行正常。”这行字。恭喜你一个最基础的Node.js Express服务器已经跑起来了3. 集成核心功能调用春联生成API服务器能跑了接下来就是实现核心功能让我们的后端去调用春联生成模型的API拿到生成的春联文本。3.1 理解API调用与HTTP客户端我们假设你已经有了一个可用的春联生成模型API端点Endpoint。这可以是一个你自己部署的模型服务也可以是某个AI平台提供的接口。关键信息通常包括API地址URL 例如https://api.example.com/generate/couplet请求方法 通常是POST请求头Headers 可能需要Content-Type: application/json有时还需要认证的Authorization头。请求体Body 一个JSON对象包含生成所需的参数比如{keywords: 春节 团圆, style: traditional}。在Node.js中我们使用axios或node-fetch这样的库来方便地发送HTTP请求。这里我们选择axios因为它功能强大且易于使用。安装它npm install axios3.2 创建API路由与控制器为了代码结构清晰我们采用MVC模型-视图-控制器的简单思想。在项目根目录创建一个routes文件夹然后在里面创建一个coupletRoutes.js文件。routes/coupletRoutes.js:const express require(express); const router express.Router(); const axios require(axios); // 导入axios // 你的春联生成API的实际地址和密钥请替换为真实信息 const API_URL YOUR_COUPLET_API_ENDPOINT; const API_KEY YOUR_API_KEY; // 如果需要的话 // 定义生成春联的路由 router.post(/generate, async (req, res) { try { // 从前端获取的请求参数比如主题词 const { keywords } req.body; // 构建请求参数具体格式需要根据你的API文档调整 const requestData { prompt: keywords || 春节 快乐, // 默认主题 max_length: 50 // 控制生成文本长度 }; // 配置请求头 const config { headers: { Content-Type: application/json, // 如果有API密钥在这里添加 // Authorization: Bearer ${API_KEY} } }; // 发送POST请求到春联生成API const apiResponse await axios.post(API_URL, requestData, config); // 假设API返回的数据结构是 { data: { couplet: 上联...下联... } } // 你需要根据实际API响应结构调整这里的代码 const generatedCouplet apiResponse.data.data?.couplet || 生成失败请重试。; // 将生成的春联返回给前端 res.json({ success: true, data: { couplet: generatedCouplet, keywords: keywords } }); } catch (error) { console.error(调用春联API失败, error.message); // 更友好的错误处理 res.status(500).json({ success: false, message: 生成春联时出现错误请稍后再试。 }); } }); module.exports router;然后我们需要在主文件app.js中引入并使用这个路由并添加解析JSON请求体的中间件。更新app.js:const express require(express); const app express(); const PORT process.env.PORT || 3000; // 新增引入春联路由 const coupletRoutes require(./routes/coupletRoutes); // 新增中间件用于解析JSON格式的请求体POST请求的数据 app.use(express.json()); // 新增中间件用于解析URL编码格式的请求体来自表单提交 app.use(express.urlencoded({ extended: true })); app.engine(html, require(ejs).renderFile); app.set(view engine, html); app.use(express.static(public)); // 修改将根路径路由改为渲染一个主页 app.get(/, (req, res) { res.render(index); // 稍后我们会创建这个视图文件 }); // 新增挂载春联生成API路由所有以 /api/couplet 开头的请求都由它处理 app.use(/api/couplet, coupletRoutes); app.listen(PORT, () { console.log(春联生成应用正在运行http://localhost:${PORT}); });现在我们的后端API就准备好了。当前端向http://localhost:3000/api/couplet/generate发送一个POST请求携带keywords参数时后端就会去调用真正的春联模型API并将结果返回。4. 打造节日界面前端页面与交互后端逻辑通了现在我们来做一个好看的、有春节氛围的前端页面让用户能输入关键词、点击按钮、然后看到生成的春联。4.1 创建视图与模板我们使用EJS作为模板引擎它允许我们在HTML中嵌入JavaScript代码动态渲染内容。首先安装EJSnpm install ejs然后修改app.js中关于视图引擎的设置将html改为ejs// 修改这行 app.set(view engine, ejs); // 原来是 html // 可以删除 app.engine 那行因为EJS是默认支持的在项目根目录创建一个views文件夹这是Express默认查找视图模板的地方。在views文件夹里创建index.ejs文件。views/index.ejs:!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleAI春联生成器 - 恭贺新禧/title link relstylesheet href/css/style.css link relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css /head body div classcontainer header classfestival-header h1i classfas fa-fire/i AI春联生成器/h1 p classsubtitle输入关键词一键生成专属春节对联为佳节添彩/p /header main classmain-content section classinput-section h2写下你的新春愿望/h2 p例如团圆、平安、富贵、学业进步/p div classinput-group input typetext idkeywords placeholder请输入春节主题关键词... value春节 快乐 button idgenerateBtn classbtn-generate i classfas fa-magic/i 生成春联 /button /div div classloading idloading styledisplay: none; i classfas fa-spinner fa-spin/i AI正在构思您的春联请稍候... /div /section section classresult-section idresultSection styledisplay: none; h2为您生成的春联/h2 div classcouplet-container div classcouplet-line idfirstLine上联将显示在这里/div div classcouplet-line idsecondLine下联将显示在这里/div div classcouplet-horizontal idhorizontal横批将显示在这里/div /div div classaction-buttons button idcopyBtn classbtn-secondaryi classfar fa-copy/i 复制文本/button button idregenerateBtn classbtn-secondaryi classfas fa-redo/i 重新生成/button /div /section div classfestival-decoration div classlantern/div div classlantern/div /div /main footer classfestival-footer p用技术传递祝福 · span idcurrentYear/span 新年快乐/p /footer /div script src/js/main.js/script script // 简单设置年份 document.getElementById(currentYear).textContent new Date().getFullYear(); /script /body /html4.2 添加样式与交互逻辑为了让页面好看我们需要一些CSS。在项目根目录创建public文件夹然后在里面创建css和js子文件夹。public/css/style.css:* { margin: 0; padding: 0; box-sizing: border-box; font-family: Segoe UI, Microsoft YaHei, sans-serif; } body { background: linear-gradient(135deg, #f9d423 0%, #ff4e50 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; color: #5a3921; } .container { background-color: rgba(255, 255, 255, 0.95); border-radius: 24px; box-shadow: 0 20px 60px rgba(186, 60, 60, 0.3); width: 100%; max-width: 800px; overflow: hidden; border: 8px solid #d62828; position: relative; } .festival-header { background: linear-gradient(to right, #d62828, #f77f00); color: white; text-align: center; padding: 2.5rem 1rem; border-bottom: 6px solid #ffd166; } .festival-header h1 { font-size: 3rem; margin-bottom: 0.5rem; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); } .subtitle { font-size: 1.2rem; opacity: 0.9; } .main-content { padding: 3rem 2rem; } .input-section, .result-section { background: #fff9f0; border-radius: 18px; padding: 2rem; margin-bottom: 2.5rem; border: 3px dashed #f4a261; box-shadow: inset 0 0 15px rgba(244, 162, 97, 0.1); } h2 { color: #d62828; margin-bottom: 1rem; font-size: 1.8rem; border-left: 6px solid #f77f00; padding-left: 15px; } .input-group { display: flex; gap: 15px; margin-top: 1.5rem; } #keywords { flex: 1; padding: 18px 20px; border: 3px solid #ffd166; border-radius: 12px; font-size: 1.1rem; outline: none; transition: all 0.3s; } #keywords:focus { border-color: #f77f00; box-shadow: 0 0 0 3px rgba(247, 127, 0, 0.2); } .btn-generate { background: linear-gradient(to bottom, #d62828, #b71c1c); color: white; border: none; padding: 18px 35px; border-radius: 12px; font-size: 1.2rem; font-weight: bold; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; gap: 10px; } .btn-generate:hover { background: linear-gradient(to bottom, #b71c1c, #8a0f0f); transform: translateY(-3px); box-shadow: 0 7px 14px rgba(214, 40, 40, 0.3); } .loading { text-align: center; margin-top: 1.5rem; color: #f77f00; font-size: 1.1rem; } .couplet-container { background: #fef7e6; border: 4px solid #d62828; border-radius: 16px; padding: 2.5rem; text-align: center; margin: 2rem 0; position: relative; } .couplet-line { font-size: 2.2rem; font-weight: bold; margin: 1.2rem 0; color: #5a3921; line-height: 1.6; font-family: KaiTi, STKaiti, serif; } .couplet-horizontal { font-size: 1.8rem; font-weight: bold; color: #d62828; margin-top: 2rem; padding-top: 1rem; border-top: 3px solid #f4a261; font-family: KaiTi, STKaiti, serif; } .action-buttons { display: flex; justify-content: center; gap: 20px; margin-top: 2rem; } .btn-secondary { background-color: #ffd166; color: #5a3921; border: none; padding: 14px 28px; border-radius: 10px; font-size: 1rem; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; gap: 8px; font-weight: bold; } .btn-secondary:hover { background-color: #f4a261; transform: translateY(-2px); } .festival-decoration { display: flex; justify-content: space-between; position: absolute; width: 100px; left: 50%; top: -30px; transform: translateX(-50%); } .lantern { width: 40px; height: 50px; background: #d62828; border-radius: 20px; position: relative; } .lantern:before, .lantern:after { content: ; position: absolute; background: #ffd166; width: 100%; height: 10px; left: 0; } .lantern:before { top: -5px; border-radius: 5px 5px 0 0; } .lantern:after { bottom: -5px; border-radius: 0 0 5px 5px; } .festival-footer { text-align: center; padding: 1.5rem; background-color: #fff9f0; color: #f77f00; border-top: 3px solid #ffd166; font-weight: bold; }public/js/main.js:document.addEventListener(DOMContentLoaded, function() { const generateBtn document.getElementById(generateBtn); const keywordsInput document.getElementById(keywords); const loadingDiv document.getElementById(loading); const resultSection document.getElementById(resultSection); const firstLineEl document.getElementById(firstLine); const secondLineEl document.getElementById(secondLine); const horizontalEl document.getElementById(horizontal); const copyBtn document.getElementById(copyBtn); const regenerateBtn document.getElementById(regenerateBtn); // 生成春联函数 async function generateCouplet() { const keywords keywordsInput.value.trim(); if (!keywords) { alert(请输入一些关键词吧); keywordsInput.focus(); return; } // 显示加载状态 loadingDiv.style.display block; generateBtn.disabled true; resultSection.style.display none; try { // 调用我们自己的后端API const response await fetch(/api/couplet/generate, { method: POST, headers: { Content-Type: application/json, }, body: JSON.stringify({ keywords: keywords }) }); const result await response.json(); if (result.success) { // 假设API返回的couplet是一个字符串包含上下联和横批用特定符号分隔 // 例如上联内容|下联内容|横批内容 const coupletText result.data.couplet; // 这里需要根据你API返回的实际格式进行解析 // 我们假设用换行符或特定分隔符分开 const lines coupletText.split(\n).filter(line line.trim()); if (lines.length 3) { firstLineEl.textContent lines[0]; secondLineEl.textContent lines[1]; horizontalEl.textContent lines[2]; } else if (lines.length 1) { // 如果只是一整句简单处理 const parts lines[0].split(); if (parts.length 2) { firstLineEl.textContent parts[0] ; secondLineEl.textContent parts[1] 。; horizontalEl.textContent result.data.keywords || 新春大吉; } else { firstLineEl.textContent lines[0]; secondLineEl.textContent 下联万象更新迎福来; horizontalEl.textContent 喜迎新春; } } else { // 默认展示内容 firstLineEl.textContent 天增岁月人增寿; secondLineEl.textContent 春满乾坤福满门; horizontalEl.textContent 四季长安; } // 显示结果区域 resultSection.style.display block; } else { alert(生成失败 (result.message || 未知错误)); } } catch (error) { console.error(请求出错, error); alert(网络或服务器错误请检查控制台。); // 演示用显示一个示例春联 firstLineEl.textContent 爆竹声中一岁除; secondLineEl.textContent 春风送暖入屠苏; horizontalEl.textContent 辞旧迎新; resultSection.style.display block; } finally { // 隐藏加载状态 loadingDiv.style.display none; generateBtn.disabled false; } } // 复制春联文本函数 function copyCoupletToClipboard() { const textToCopy ${firstLineEl.textContent}\n${secondLineEl.textContent}\n${horizontalEl.textContent}; navigator.clipboard.writeText(textToCopy).then(() { // 简单提示 const originalText copyBtn.innerHTML; copyBtn.innerHTML i classfas fa-check/i 已复制; setTimeout(() { copyBtn.innerHTML originalText; }, 2000); }).catch(err { console.error(复制失败: , err); alert(复制失败请手动选择文本复制。); }); } // 绑定按钮事件 generateBtn.addEventListener(click, generateCouplet); copyBtn.addEventListener(click, copyCoupletToClipboard); regenerateBtn.addEventListener(click, generateCouplet); // 重新生成 // 按回车键也可以触发生成 keywordsInput.addEventListener(keypress, function(e) { if (e.key Enter) { generateCouplet(); } }); // 页面加载后可以自动生成一个默认的 // setTimeout(generateCouplet, 500); // 可选自动生成 });5. 联调测试与部署上线至此一个完整的全栈应用就构建好了。让我们来测试一下整个流程。启动服务器确保在项目根目录下运行npm run dev。访问应用打开浏览器访问http://localhost:3000。你应该能看到一个喜庆的春节风格页面。测试功能在输入框里输入“团圆 幸福”点击“生成春联”按钮。你会看到加载动画然后如果后端API已正确配置并连通页面上会显示出生成的春联。测试复制功能点击“复制文本”按钮然后粘贴到记事本里检查是否正确。检查后端日志在终端里你应该能看到Node.js服务器的访问日志以及调用外部API时的成功或错误信息。关于API的特别说明上面的代码中YOUR_COUPLET_API_ENDPOINT和YOUR_API_KEY需要替换成你实际可用的春联生成模型服务地址和密钥。你可以搜索并选择提供此类服务的AI平台或者如果你有技术能力可以自行部署一个开源的文本生成模型如ChatGLM、Qwen等并封装成API。部署上线当你本地开发测试完成后可以考虑将应用部署到云服务器如阿里云ECS、腾讯云CVM或云平台如Heroku、Vercel、Railway。基本步骤包括在服务器上安装Node.js环境。将你的代码上传到服务器通常使用Git。安装依赖npm install。使用npm start启动应用或者使用pm2这样的进程管理工具来保持应用持续运行。配置域名和SSL证书可选但推荐。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
春联生成模型-中文-base与Node.js全栈开发:快速构建节日应用
春联生成模型-中文-base与Node.js全栈开发快速构建节日应用春节将至想给你的网站或应用增添一点节日气氛吗或者你正在寻找一个有趣又实用的项目来练手全栈开发今天我们就来聊聊如何用Node.js和Express快速搭建一个能自动生成春联的Web应用。整个过程不复杂即使你刚接触Node.js不久跟着步骤走也能轻松搞定。这个应用的核心是集成一个专门生成中文春联的AI模型。我们不需要自己训练模型而是通过调用现成的模型服务API让后端Node.js应用去请求然后把生成的、充满节日祝福的春联漂亮地展示在前端页面上。从环境搭建到页面渲染我们将一步步走完一个典型全栈应用的开发流程。你会发现用Node.js构建这样的趣味应用既高效又有成就感。1. 从零开始搭建你的Node.js开发环境工欲善其事必先利其器。在写代码之前我们得先把“战场”布置好。对于Node.js开发来说环境配置非常简单。1.1 安装Node.js和npmNode.js是运行JavaScript的服务器环境而npmNode Package Manager是随Node.js一同安装的包管理工具我们之后安装各种依赖库全靠它。首先访问Node.js官方网站的下载页面。你会看到两个版本LTS长期支持版和Current最新特性版。对于学习和生产环境我强烈建议选择LTS版本它更稳定兼容性更好。下载对应你操作系统Windows、macOS或Linux的安装程序然后像安装普通软件一样运行它。安装过程中基本保持默认选项即可确保“Add to PATH”这一项是被勾选的这样你才能在命令行里直接使用node和npm命令。安装完成后我们来验证一下。打开你的终端Windows上是CMD或PowerShellmacOS/Linux上是Terminal输入以下两个命令node -v npm -v如果安装成功命令行会分别显示Node.js和npm的版本号比如v18.17.0和9.6.7。看到版本号就说明你的环境已经准备就绪了。1.2 初始化你的项目环境好了接下来创建一个专属的项目目录。在终端里导航到你习惯存放代码的文件夹然后执行mkdir spring-festival-app cd spring-festival-app现在我们在这个空文件夹里初始化一个新的Node.js项目npm init -y这个命令会快速生成一个package.json文件它是你项目的“身份证”和“说明书”里面记录了项目名称、版本、描述以及最重要的——项目依赖。-y参数表示接受所有默认选项省去了一路回车确认的麻烦。2. 构建应用骨架Express框架与基础结构有了项目基础我们开始搭建应用的“骨架”。这里我们选择Express它是Node.js生态里最流行、最轻量的Web应用框架能极大简化HTTP服务器、路由等功能的开发。2.1 安装核心依赖在项目根目录下运行以下命令来安装Expressnpm install express安装完成后你会看到项目里多了一个node_modules文件夹存放所有安装的库和package-lock.json文件锁定依赖版本确保一致性。为了让开发更便捷我们还需要一个工具nodemon。它能监听文件变化自动重启Node.js应用这样我们每次修改代码后就不用手动重启服务器了。我们把它作为“开发依赖”安装npm install --save-dev nodemon2.2 创建应用入口文件接下来在项目根目录创建一个名为app.js的文件这将是我们的主应用文件。打开app.js写入以下基础代码// 导入express框架 const express require(express); // 创建一个Express应用实例 const app express(); // 定义服务器监听的端口号优先使用环境变量PORT没有则用3000 const PORT process.env.PORT || 3000; // 设置模板引擎这里先用简单的HTML稍后解释 app.engine(html, require(ejs).renderFile); app.set(view engine, html); // 设置静态文件目录这样浏览器才能访问到CSS、JS、图片等文件 app.use(express.static(public)); // 定义一个最简单的路由当用户访问网站根路径时 app.get(/, (req, res) { // 先返回一个简单的文本响应测试服务器是否工作 res.send(春节快乐Node.js服务器运行正常。); }); // 启动服务器开始监听指定端口 app.listen(PORT, () { console.log(春联生成应用正在运行http://localhost:${PORT}); });现在让我们修改package.json文件添加一个启动脚本方便我们用nodemon来运行应用。找到package.json里的scripts部分修改或添加如下内容scripts: { start: node app.js, dev: nodemon app.js }回到终端运行npm run dev。如果看到“春联生成应用正在运行http://localhost:3000”的提示就说明成功了。打开浏览器访问http://localhost:3000你应该能看到“春节快乐Node.js服务器运行正常。”这行字。恭喜你一个最基础的Node.js Express服务器已经跑起来了3. 集成核心功能调用春联生成API服务器能跑了接下来就是实现核心功能让我们的后端去调用春联生成模型的API拿到生成的春联文本。3.1 理解API调用与HTTP客户端我们假设你已经有了一个可用的春联生成模型API端点Endpoint。这可以是一个你自己部署的模型服务也可以是某个AI平台提供的接口。关键信息通常包括API地址URL 例如https://api.example.com/generate/couplet请求方法 通常是POST请求头Headers 可能需要Content-Type: application/json有时还需要认证的Authorization头。请求体Body 一个JSON对象包含生成所需的参数比如{keywords: 春节 团圆, style: traditional}。在Node.js中我们使用axios或node-fetch这样的库来方便地发送HTTP请求。这里我们选择axios因为它功能强大且易于使用。安装它npm install axios3.2 创建API路由与控制器为了代码结构清晰我们采用MVC模型-视图-控制器的简单思想。在项目根目录创建一个routes文件夹然后在里面创建一个coupletRoutes.js文件。routes/coupletRoutes.js:const express require(express); const router express.Router(); const axios require(axios); // 导入axios // 你的春联生成API的实际地址和密钥请替换为真实信息 const API_URL YOUR_COUPLET_API_ENDPOINT; const API_KEY YOUR_API_KEY; // 如果需要的话 // 定义生成春联的路由 router.post(/generate, async (req, res) { try { // 从前端获取的请求参数比如主题词 const { keywords } req.body; // 构建请求参数具体格式需要根据你的API文档调整 const requestData { prompt: keywords || 春节 快乐, // 默认主题 max_length: 50 // 控制生成文本长度 }; // 配置请求头 const config { headers: { Content-Type: application/json, // 如果有API密钥在这里添加 // Authorization: Bearer ${API_KEY} } }; // 发送POST请求到春联生成API const apiResponse await axios.post(API_URL, requestData, config); // 假设API返回的数据结构是 { data: { couplet: 上联...下联... } } // 你需要根据实际API响应结构调整这里的代码 const generatedCouplet apiResponse.data.data?.couplet || 生成失败请重试。; // 将生成的春联返回给前端 res.json({ success: true, data: { couplet: generatedCouplet, keywords: keywords } }); } catch (error) { console.error(调用春联API失败, error.message); // 更友好的错误处理 res.status(500).json({ success: false, message: 生成春联时出现错误请稍后再试。 }); } }); module.exports router;然后我们需要在主文件app.js中引入并使用这个路由并添加解析JSON请求体的中间件。更新app.js:const express require(express); const app express(); const PORT process.env.PORT || 3000; // 新增引入春联路由 const coupletRoutes require(./routes/coupletRoutes); // 新增中间件用于解析JSON格式的请求体POST请求的数据 app.use(express.json()); // 新增中间件用于解析URL编码格式的请求体来自表单提交 app.use(express.urlencoded({ extended: true })); app.engine(html, require(ejs).renderFile); app.set(view engine, html); app.use(express.static(public)); // 修改将根路径路由改为渲染一个主页 app.get(/, (req, res) { res.render(index); // 稍后我们会创建这个视图文件 }); // 新增挂载春联生成API路由所有以 /api/couplet 开头的请求都由它处理 app.use(/api/couplet, coupletRoutes); app.listen(PORT, () { console.log(春联生成应用正在运行http://localhost:${PORT}); });现在我们的后端API就准备好了。当前端向http://localhost:3000/api/couplet/generate发送一个POST请求携带keywords参数时后端就会去调用真正的春联模型API并将结果返回。4. 打造节日界面前端页面与交互后端逻辑通了现在我们来做一个好看的、有春节氛围的前端页面让用户能输入关键词、点击按钮、然后看到生成的春联。4.1 创建视图与模板我们使用EJS作为模板引擎它允许我们在HTML中嵌入JavaScript代码动态渲染内容。首先安装EJSnpm install ejs然后修改app.js中关于视图引擎的设置将html改为ejs// 修改这行 app.set(view engine, ejs); // 原来是 html // 可以删除 app.engine 那行因为EJS是默认支持的在项目根目录创建一个views文件夹这是Express默认查找视图模板的地方。在views文件夹里创建index.ejs文件。views/index.ejs:!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleAI春联生成器 - 恭贺新禧/title link relstylesheet href/css/style.css link relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css /head body div classcontainer header classfestival-header h1i classfas fa-fire/i AI春联生成器/h1 p classsubtitle输入关键词一键生成专属春节对联为佳节添彩/p /header main classmain-content section classinput-section h2写下你的新春愿望/h2 p例如团圆、平安、富贵、学业进步/p div classinput-group input typetext idkeywords placeholder请输入春节主题关键词... value春节 快乐 button idgenerateBtn classbtn-generate i classfas fa-magic/i 生成春联 /button /div div classloading idloading styledisplay: none; i classfas fa-spinner fa-spin/i AI正在构思您的春联请稍候... /div /section section classresult-section idresultSection styledisplay: none; h2为您生成的春联/h2 div classcouplet-container div classcouplet-line idfirstLine上联将显示在这里/div div classcouplet-line idsecondLine下联将显示在这里/div div classcouplet-horizontal idhorizontal横批将显示在这里/div /div div classaction-buttons button idcopyBtn classbtn-secondaryi classfar fa-copy/i 复制文本/button button idregenerateBtn classbtn-secondaryi classfas fa-redo/i 重新生成/button /div /section div classfestival-decoration div classlantern/div div classlantern/div /div /main footer classfestival-footer p用技术传递祝福 · span idcurrentYear/span 新年快乐/p /footer /div script src/js/main.js/script script // 简单设置年份 document.getElementById(currentYear).textContent new Date().getFullYear(); /script /body /html4.2 添加样式与交互逻辑为了让页面好看我们需要一些CSS。在项目根目录创建public文件夹然后在里面创建css和js子文件夹。public/css/style.css:* { margin: 0; padding: 0; box-sizing: border-box; font-family: Segoe UI, Microsoft YaHei, sans-serif; } body { background: linear-gradient(135deg, #f9d423 0%, #ff4e50 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; color: #5a3921; } .container { background-color: rgba(255, 255, 255, 0.95); border-radius: 24px; box-shadow: 0 20px 60px rgba(186, 60, 60, 0.3); width: 100%; max-width: 800px; overflow: hidden; border: 8px solid #d62828; position: relative; } .festival-header { background: linear-gradient(to right, #d62828, #f77f00); color: white; text-align: center; padding: 2.5rem 1rem; border-bottom: 6px solid #ffd166; } .festival-header h1 { font-size: 3rem; margin-bottom: 0.5rem; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); } .subtitle { font-size: 1.2rem; opacity: 0.9; } .main-content { padding: 3rem 2rem; } .input-section, .result-section { background: #fff9f0; border-radius: 18px; padding: 2rem; margin-bottom: 2.5rem; border: 3px dashed #f4a261; box-shadow: inset 0 0 15px rgba(244, 162, 97, 0.1); } h2 { color: #d62828; margin-bottom: 1rem; font-size: 1.8rem; border-left: 6px solid #f77f00; padding-left: 15px; } .input-group { display: flex; gap: 15px; margin-top: 1.5rem; } #keywords { flex: 1; padding: 18px 20px; border: 3px solid #ffd166; border-radius: 12px; font-size: 1.1rem; outline: none; transition: all 0.3s; } #keywords:focus { border-color: #f77f00; box-shadow: 0 0 0 3px rgba(247, 127, 0, 0.2); } .btn-generate { background: linear-gradient(to bottom, #d62828, #b71c1c); color: white; border: none; padding: 18px 35px; border-radius: 12px; font-size: 1.2rem; font-weight: bold; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; gap: 10px; } .btn-generate:hover { background: linear-gradient(to bottom, #b71c1c, #8a0f0f); transform: translateY(-3px); box-shadow: 0 7px 14px rgba(214, 40, 40, 0.3); } .loading { text-align: center; margin-top: 1.5rem; color: #f77f00; font-size: 1.1rem; } .couplet-container { background: #fef7e6; border: 4px solid #d62828; border-radius: 16px; padding: 2.5rem; text-align: center; margin: 2rem 0; position: relative; } .couplet-line { font-size: 2.2rem; font-weight: bold; margin: 1.2rem 0; color: #5a3921; line-height: 1.6; font-family: KaiTi, STKaiti, serif; } .couplet-horizontal { font-size: 1.8rem; font-weight: bold; color: #d62828; margin-top: 2rem; padding-top: 1rem; border-top: 3px solid #f4a261; font-family: KaiTi, STKaiti, serif; } .action-buttons { display: flex; justify-content: center; gap: 20px; margin-top: 2rem; } .btn-secondary { background-color: #ffd166; color: #5a3921; border: none; padding: 14px 28px; border-radius: 10px; font-size: 1rem; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; gap: 8px; font-weight: bold; } .btn-secondary:hover { background-color: #f4a261; transform: translateY(-2px); } .festival-decoration { display: flex; justify-content: space-between; position: absolute; width: 100px; left: 50%; top: -30px; transform: translateX(-50%); } .lantern { width: 40px; height: 50px; background: #d62828; border-radius: 20px; position: relative; } .lantern:before, .lantern:after { content: ; position: absolute; background: #ffd166; width: 100%; height: 10px; left: 0; } .lantern:before { top: -5px; border-radius: 5px 5px 0 0; } .lantern:after { bottom: -5px; border-radius: 0 0 5px 5px; } .festival-footer { text-align: center; padding: 1.5rem; background-color: #fff9f0; color: #f77f00; border-top: 3px solid #ffd166; font-weight: bold; }public/js/main.js:document.addEventListener(DOMContentLoaded, function() { const generateBtn document.getElementById(generateBtn); const keywordsInput document.getElementById(keywords); const loadingDiv document.getElementById(loading); const resultSection document.getElementById(resultSection); const firstLineEl document.getElementById(firstLine); const secondLineEl document.getElementById(secondLine); const horizontalEl document.getElementById(horizontal); const copyBtn document.getElementById(copyBtn); const regenerateBtn document.getElementById(regenerateBtn); // 生成春联函数 async function generateCouplet() { const keywords keywordsInput.value.trim(); if (!keywords) { alert(请输入一些关键词吧); keywordsInput.focus(); return; } // 显示加载状态 loadingDiv.style.display block; generateBtn.disabled true; resultSection.style.display none; try { // 调用我们自己的后端API const response await fetch(/api/couplet/generate, { method: POST, headers: { Content-Type: application/json, }, body: JSON.stringify({ keywords: keywords }) }); const result await response.json(); if (result.success) { // 假设API返回的couplet是一个字符串包含上下联和横批用特定符号分隔 // 例如上联内容|下联内容|横批内容 const coupletText result.data.couplet; // 这里需要根据你API返回的实际格式进行解析 // 我们假设用换行符或特定分隔符分开 const lines coupletText.split(\n).filter(line line.trim()); if (lines.length 3) { firstLineEl.textContent lines[0]; secondLineEl.textContent lines[1]; horizontalEl.textContent lines[2]; } else if (lines.length 1) { // 如果只是一整句简单处理 const parts lines[0].split(); if (parts.length 2) { firstLineEl.textContent parts[0] ; secondLineEl.textContent parts[1] 。; horizontalEl.textContent result.data.keywords || 新春大吉; } else { firstLineEl.textContent lines[0]; secondLineEl.textContent 下联万象更新迎福来; horizontalEl.textContent 喜迎新春; } } else { // 默认展示内容 firstLineEl.textContent 天增岁月人增寿; secondLineEl.textContent 春满乾坤福满门; horizontalEl.textContent 四季长安; } // 显示结果区域 resultSection.style.display block; } else { alert(生成失败 (result.message || 未知错误)); } } catch (error) { console.error(请求出错, error); alert(网络或服务器错误请检查控制台。); // 演示用显示一个示例春联 firstLineEl.textContent 爆竹声中一岁除; secondLineEl.textContent 春风送暖入屠苏; horizontalEl.textContent 辞旧迎新; resultSection.style.display block; } finally { // 隐藏加载状态 loadingDiv.style.display none; generateBtn.disabled false; } } // 复制春联文本函数 function copyCoupletToClipboard() { const textToCopy ${firstLineEl.textContent}\n${secondLineEl.textContent}\n${horizontalEl.textContent}; navigator.clipboard.writeText(textToCopy).then(() { // 简单提示 const originalText copyBtn.innerHTML; copyBtn.innerHTML i classfas fa-check/i 已复制; setTimeout(() { copyBtn.innerHTML originalText; }, 2000); }).catch(err { console.error(复制失败: , err); alert(复制失败请手动选择文本复制。); }); } // 绑定按钮事件 generateBtn.addEventListener(click, generateCouplet); copyBtn.addEventListener(click, copyCoupletToClipboard); regenerateBtn.addEventListener(click, generateCouplet); // 重新生成 // 按回车键也可以触发生成 keywordsInput.addEventListener(keypress, function(e) { if (e.key Enter) { generateCouplet(); } }); // 页面加载后可以自动生成一个默认的 // setTimeout(generateCouplet, 500); // 可选自动生成 });5. 联调测试与部署上线至此一个完整的全栈应用就构建好了。让我们来测试一下整个流程。启动服务器确保在项目根目录下运行npm run dev。访问应用打开浏览器访问http://localhost:3000。你应该能看到一个喜庆的春节风格页面。测试功能在输入框里输入“团圆 幸福”点击“生成春联”按钮。你会看到加载动画然后如果后端API已正确配置并连通页面上会显示出生成的春联。测试复制功能点击“复制文本”按钮然后粘贴到记事本里检查是否正确。检查后端日志在终端里你应该能看到Node.js服务器的访问日志以及调用外部API时的成功或错误信息。关于API的特别说明上面的代码中YOUR_COUPLET_API_ENDPOINT和YOUR_API_KEY需要替换成你实际可用的春联生成模型服务地址和密钥。你可以搜索并选择提供此类服务的AI平台或者如果你有技术能力可以自行部署一个开源的文本生成模型如ChatGLM、Qwen等并封装成API。部署上线当你本地开发测试完成后可以考虑将应用部署到云服务器如阿里云ECS、腾讯云CVM或云平台如Heroku、Vercel、Railway。基本步骤包括在服务器上安装Node.js环境。将你的代码上传到服务器通常使用Git。安装依赖npm install。使用npm start启动应用或者使用pm2这样的进程管理工具来保持应用持续运行。配置域名和SSL证书可选但推荐。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。