用OpenAI接口给女朋友手搓AI小助理,她说要奖励我,结果……

前言

最近,我那财经系的小女友迎来了考试周,她的复习资料已经堆得像珠穆朗玛峰一样高。压力山大的她不断让我帮她整理这些资料,还频频向我倾诉她的苦水。虽然我自己也挺忙的,但为了爱,我只能忍痛扛起这重担。。。为了减轻我的负担,我向小女友推荐了几个国内的AI网站,让她去找那些冰冷无情但聪明绝顶的机器人求助。虽然整理资料的任务是轻了不少,但她的吐槽却是有增无减,搞得我快成了她的专属垃圾桶。

于是乎,我灵机一动,决定利用OpenAI接口,亲手给她打造一个专属AI小助理。接下来,我将详细介绍如何建立一个小型的网页AI小助理,包括前后端的交互。希望这篇文章不仅能帮你减轻工作量,还能为你的女朋友赚取一些甜蜜的奖励哦!

天才第一步:雀氏。。。一个优雅简洁且可爱的前端界面

首先,我们需要一个前端界面来让亲爱的小女友与AI助手进行互动。下面是一个HTML和CSS的例子,它提供了一个可爱的聊天框和一个还算可爱的输入框,小女友可以在这里键入她的问题并发送给AI助手。话不多说,先上示例图。为了不影响大伙的阅读体验,前端界面的全部代码我就放在文章末尾了。

image.png

第二步:后端-AI助手的大脑

后端部分,我们在当前文件夹下建立一个ai.js文件,使用Node.js和Express来处理与OpenAI的交互。首先,确保你已经安装了必要的依赖包。打开你的终端,输入以下命令:

npm init -y
npm install express body-parser openai dotenv cors

1. 导入必要的模块

const express = require("express");
const bodyParser = require("body-parser");
const OpenAI = require("openai");
const dotenv = require("dotenv");
dotenv.config();

这段代码就像是在召唤超级英雄一样,依次叫来了Express、body-parser和OpenAI模块,还顺便引入了dotenv来加载环境变量。这样我们就能通过process.env来访问我们的OpenAI API密钥了。 随后在当前文件夹下建立一个.env文件,用来存放我们一些不可见人的小秘密数据,比如PORT端口和OPENAI_KEY。

image.png


2. 配置OpenAI客户端

const openai = new OpenAI({
  apiKey: process.env.OPENAI_KEY,
  baseURL: "https://api.302.ai/v1",
});

这里,我们配置了OpenAI客户端。apiKey是你的OpenAI密钥,baseURL则是API的地址。这里使用的是302AI的API代理,完全对齐OpenAI的API。至于为什么,因为原生的OpenAI需要绑一张海外信用卡,且充值进去才能用。。。


3. 设置Express应用

const app = express();
const port = process.env.PORT || 3000;

我们创建了一个Express应用实例,并设置了端口。这里使用了环境变量中的端口号,如果没有设置环境变量,则默认使用3000端口。


4. 中间件配置

app.use(bodyParser.json());
app.use(cors());


这里,我们配置了两个中间件。bodyParser.json()用于解析JSON请求体,而cors()则是用来启用跨域资源共享,这样我们就可以从不同的域名访问我们的API了。

5. 初始化聊天历史

let chatHistory = [{ role: "system", content: "You are a helpful assistant." }];

为了让我们的AI助手能有一些上下文,我们初始化了一个聊天历史数组。第一条消息是由“系统”发送的,告诉AI它是一个乐于助人的助手。就像是给AI设定了一个友好的开场白。


6. 处理用户消息

app.post("/chat", async (req, res) => {
  const userMessage = req.body.message;
  chatHistory.push({ role: "user", content: userMessage });

  try {
    const completion = await openai.chat.completions.create({
      messages: chatHistory,
      model: "gpt-3.5-turbo",
    });

    const aiMessage = completion.choices[0].message.content;
    chatHistory.push({ role: "assistant", content: aiMessage });

    res.json({ aiMessage, chatHistory });
  } catch (error) {
    res.status(500).send("处理请求时发生错误。");
  }
});

这里,我们定义了一个处理POST请求的路由/chat。当用户发送消息时:

  1. 从请求体中获取用户的消息userMessage,并将其添加到聊天历史中。
  2. 调用OpenAI的API生成回复。具体来说,调用了chat.completions.create方法,并传递了当前的聊天历史和所使用的模型。
  3. 将AI的回复添加到聊天历史中,然后将AI的回复和更新后的聊天历史返回给前端。

如果在处理过程中遇到错误,我们会返回一个500状态码,并在响应中发送错误信息。


7. 启动服务器

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

最后,我们启动了服务器,让它在指定端口上监听。这样,我们的AI助手就正式上线了!你可以访问这个ip地址,与这个小猫老弟智能助手进行愉快的对话。

第三步:前端与后端之间的小小润滑

1. 准备工作

document.addEventListener("DOMContentLoaded", function () {
  // ...
}


首先,我们需要确保页面加载完成后再执行代码。这就是DOMContentLoaded事件的作用,确保页面所有元素都已经加载完毕。


2. 获取元素和初始化

const sendButton = document.querySelector(".button--submit");
const closeButton = document.querySelector(".button--close-window");
const chatBox = document.getElementById("ai-window-chatbox");
const placeholder = document.querySelector(".ai-placeholder");
const overlay = document.querySelector(".overlay");
const openAiButton = document.querySelector(".button--openai");
const aiWindow = document.querySelector(".ai-window");
const textarea = document.getElementById("ai-window-userInput");


这些变量就像是我们要控制的道具箱,每个按钮和输入框都有它独特的功能,为用户提供最佳的体验。


3. 调整文本框的高度

function adjustHeight() {
  const minHeight = 35;
  textarea.style.height = minHeight + "px";
  textarea.style.height = Math.max(minHeight, Math.min(textarea.scrollHeight, 180)) + "px";
}

textarea.addEventListener("input", adjustHeight);
adjustHeight();


这里的作用是不断地调整输入框的高度,确保它既不会太矮,也不会太高。我们希望它看起来刚刚好,保持优雅。


4. 发送消息的函数

async function sendMessage() {
  // 获取用户输入,空则退出函数
  const message = textarea.value.trim();
  if (!message) return;
  
  // 清空输入框内容,调正输入框高度,隐藏小猫老弟,展示聊天内容
  textarea.value = "";
  adjustHeight();
  if (placeholder) {
    placeholder.style.display = "none";
  }
  
  // 将用户发送内容添加进聊天记录,并将内容md语法化
  const userMessageHTML = `<div class="message user"><strong>你:</strong> ${marked.parse(message)}</div>`;
  chatBox.innerHTML += userMessageHTML;
  
  // 禁用发送按钮
  sendButton.disabled = true;

  try {
    // 获取AI回复,这里向app监听的端口发送请求
    const response = await fetch("http://localhost:3000/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message }),
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    // 拿到回复数据,将其md语法化之后添加进聊天记录
    const data = await response.json();
    const aiMessage = data.aiMessage;
    const aiMessageHTML = `<div class="message assistant"><strong>小猫:</strong> ${marked.parse(aiMessage)}</div>`;
    chatBox.innerHTML += aiMessageHTML;
  } catch (error) {
    // 打印错误到控制台,并且在页面上显示系统出错
    console.error("Fetch Error:", error);
    const errorMessageHTML = `<div class="message system"><strong>系统:</strong> 出错了,请稍后再试。</div>`;
    chatBox.innerHTML += errorMessageHTML;
  } finally {
    // 启用发送按钮
    sendButton.disabled = false;
  }

  // 滚动到底部显示最新消息
  chatBox.scrollTop = chatBox.scrollHeight;
}


发送消息的过程就像一场激动人心的告白,你输入内容,点击发送,心跳加速等待对方的回复。代码中,我们首先获取用户输入,清空输入框,并调整高度。如果有内容,则发送给服务器,等待 AI 的回应。如果出错了,也会优雅地告诉你“系统出错了,请稍后再试”。


5. 添加事件监听器

sendButton.addEventListener("click", sendMessage);
textarea.addEventListener("keydown", (e) => {
  if (e.key === "Enter" && !e.shiftKey) {
    e.preventDefault();
    sendMessage();
  }
});


我们绑定了点击发送按钮和按下回车键的事件。除此之外我们可以用shift + enter来进行换行


6. 关闭按钮和模糊背景点击事件

// 关闭窗口事件
closeButton.addEventListener("click", () => {
  aiWindow.classList.add("hidden");
  overlay.classList.add("hidden");
});

overlay.addEventListener("click", () => {
  aiWindow.classList.add("hidden");
  overlay.classList.add("hidden");
});

// 打开窗口事件
openAiButton.addEventListener("click", () => {
  aiWindow.classList.remove("hidden");
  overlay.classList.remove("hidden");
});


点击关闭按钮或遮罩层,AI 窗口和背景同时消失。点击打开按钮,AI 窗口和背景同时出现。

结尾

以上就是手搓一个AI小助理的全过程!完成后我将这个小程序应用到了写给女朋友的网站上,女朋友访问后开心的像个傻子,说要好好的疼爱疼爱我。。。不说了,逛商城了。

最后,希望大伙能从中获得灵感,让生活变得更加智能和有趣。如果你也有类似的需求,不妨试试这个小项目,享受AI带来的便利和乐趣吧!

最后的最后,祝大家都能顺利完成任务,收获意外的惊喜和奖励!

image.png (也是被AI正义执行了。。。)


HTML主要代码

    <div class="ai-window flex-col al-center jtf-space-B hidden">
      <button class="button--close-window">&times;</button>
      <div id="ai-window-chatbox" class="ai-chatbox flex-col al-center">
        <div class="ai-placeholder flex-col al-center jtf-center">
          <img
            width="64"
            src="https://img.icons8.com/pastel-glyph/64/000000/cat--v2.png"
            alt="cat--v2"
          />
          <p>需要帮助吗?请向我提问!</p>
        </div>
      </div>

      <div class="ai-userInput-box flex al-center jtf-space-B">
        <textarea
          rows="1"
          id="ai-window-userInput"
          placeholder="给小猫老弟发送消息"
          class="ai-userInput"
        ></textarea>
        <button class="button--submit">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
            class="send-icon"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18"
            />
          </svg>
        </button>
      </div>
    </div>

    <div class="overlay hidden"></div>

    <button class="button--openai">
      <img
        width="48"
        src="https://img.icons8.com/pastel-glyph/64/000000/cat--v2.png"
        alt="cat--v2"
      />
    </button>


CSS代码

/*******************************/
/******* 全局设置 *******/
/*******************************/
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 62.5%;
}

body {
  font-family: "Poppins", "ZCOOL XiaoWei", sans-serif;
  color: rgb(255, 255, 255, 0.8);
}

/*******************************/
/******* AI助理部分 *******/
/*******************************/
.button--openai {
  border: none;
  background-color: #f7f6f6;
  width: 6.4rem;
  height: 6.4rem;
  padding: 8px;
  cursor: pointer;
  position: absolute;
  border-radius: 50%;
  box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.2);
  bottom: 7%;
  right: 5%;
  transition: all 0.2s;
}

.button--openai:hover {
  background-color: rgba(247, 246, 246, 0.6);
}

.button--openai img {
  position: absolute;
  top: 0;
  left: 8%;
}

.ai-window {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 70%;
  height: 80%;
  background-color: #fff;
  padding: 6rem;
  border-radius: 5px;
  box-shadow: 0 3rem 5rem rgba(0, 0, 0, 0.3);
  z-index: 10;
}

.button--close-window {
  position: absolute;
  top: 2rem;
  right: 3.2rem;
  font-size: 5rem;
  color: #333;
  cursor: pointer;
  border: none;
  background: none;
}

.ai-chatbox {
  width: 90%;
  height: 80%;
  color: #333;
  overflow-y: auto;
}

.ai-placeholder {
  height: 100%;
  text-align: center;
  font-size: 1.6rem;
}

.ai-userInput-box {
  width: 90%;
  color: #000;
  padding: 8px 10px;
  font-family: sans-serif;
  background-color: #efefef;
  border-radius: 26px;
}

.ai-userInput {
  border: none;
  background-color: transparent;
  width: 90%;
  padding: 8px 12px;
  font-size: 1.6rem;
  overflow-y: auto;
  resize: none;
}

.ai-userInput:focus {
  outline: none;
}

.button--submit {
  width: 3.2rem;
  height: 3.2rem;
  border: none;
  background-color: #000;
  border-radius: 50%;
  padding: 5px;
  color: white;
  cursor: pointer;
  transition: all 0.1s;
}

.button--submit:hover {
  background-color: rgba(0, 0, 0, 0.6);
}

.message {
  font-size: 1.6rem;
  width: initial;
  margin: 10px;
  padding: 10px;
  border-radius: 10px;
}

.message.user {
  background-color: #d1e7dd;
  align-self: flex-end;
}

.message.assistant {
  background-color: #f8d7da;
  align-self: flex-start;
}

.message.system {
  background-color: #fff3cd;
  align-self: center;
  text-align: center;
}

/*******************************/
/******* 工具类部分 *******/
/*******************************/

.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(3px);
  z-index: 5;
}

.hidden {
  display: none !important;
}

.flex {
  display: flex;
}

.flex-col {
  display: flex;
  flex-direction: column;
}

.al-center {
  align-items: center;
}

.jtf-center {
  justify-content: center;
}

.jtf-space-A {
  justify-content: space-around;
}

.jtf-space-B {
  justify-content: space-between;
}



ai.js代码

const express = require("express");
const bodyParser = require("body-parser");
const OpenAI = require("openai");
const cors = require("cors");
const dotenv = require("dotenv");
dotenv.config();

const openai = new OpenAI({
  apiKey: process.env.OPENAI_KEY,
  baseURL: "https://api.302.ai/v1",
});

const app = express();
const port = process.env.PORT || 3000;

app.use(bodyParser.json());

app.use(cors());

let chatHistory = [{ role: "system", content: "You are a helpful assistant." }];

app.post("/chat", async (req, res) => {
  const userMessage = req.body.message;
  chatHistory.push({ role: "user", content: userMessage });

  try {
    const completion = await openai.chat.completions.create({
      messages: chatHistory,
      model: "gpt-3.5-turbo",
    });

    const aiMessage = completion.choices[0].message.content;
    chatHistory.push({ role: "assistant", content: aiMessage });

    res.json({ aiMessage, chatHistory });
  } catch (error) {
    res.status(500).send("处理请求时发生错误。");
  }
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});



script.js(前端引用)代码

"use strict";

document.addEventListener("DOMContentLoaded", function () {
  const sendButton = document.querySelector(".button--submit");
  const closeButton = document.querySelector(".button--close-window");
  const chatBox = document.getElementById("ai-window-chatbox");
  const placeholder = document.querySelector(".ai-placeholder");
  const overlay = document.querySelector(".overlay");
  const openAiButton = document.querySelector(".button--openai");
  const aiWindow = document.querySelector(".ai-window");
  const textarea = document.getElementById("ai-window-userInput");

  function adjustHeight() {
    const minHeight = 35;

    textarea.style.height = minHeight + "px";

    textarea.style.height =
      Math.max(minHeight, Math.min(textarea.scrollHeight, 180)) + "px";
  }

  textarea.addEventListener("input", adjustHeight);
  adjustHeight(); // 初始化调整高度

  async function sendMessage() {
    const message = textarea.value.trim();
    if (!message) return;

    textarea.value = "";
    adjustHeight();

    if (placeholder) {
      placeholder.style.display = "none";
    }

    const userMessageHTML = `<div class="message user"><strong>你:</strong> ${marked.parse(
      message
    )}</div>`;
    chatBox.innerHTML += userMessageHTML;

    sendButton.disabled = true;

    try {
      const response = await fetch("http://localhost:3000/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ message }),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data = await response.json();
      const aiMessage = data.aiMessage;
      const aiMessageHTML = `<div class="message assistant"><strong>小猫:</strong> ${marked.parse(
        aiMessage
      )}</div>`;

      chatBox.innerHTML += aiMessageHTML;
    } catch (error) {
      console.error("Fetch Error:", error);
      const errorMessageHTML = `<div class="message system"><strong>系统:</strong> 出错了,请稍后再试。</div>`;
      chatBox.innerHTML += errorMessageHTML;
    } finally {
      sendButton.disabled = false;
    }

    chatBox.scrollTop = chatBox.scrollHeight;
  }

  sendButton.addEventListener("click", sendMessage);
  textarea.addEventListener("keydown", (e) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  });

  closeButton.addEventListener("click", () => {
    aiWindow.classList.add("hidden");
    overlay.classList.add("hidden");
  });

  overlay.addEventListener("click", () => {
    aiWindow.classList.add("hidden");
    overlay.classList.add("hidden");
  });

  openAiButton.addEventListener("click", () => {
    aiWindow.classList.remove("hidden");
    overlay.classList.remove("hidden");
  });
});


如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值