java接入AI大模型个人实践(二)

今天浅浅的讲一下前端如何接收流式接口,由于本人是个前端小白,以下功能只实现了基础的对话交流,具体的交互和样式暂且不考虑。

直接上代码

<template>
  <div class="app-container">
    <!-- Welcome Message -->
    <div class="welcome-message">
      <p>您好!我是您的数字助理</p>
      <p>我可以为你解答各类问题、生成图片、总结文档等。</p>
      <p>有任何需要,请随时对我说~~😉</p>
    </div>

    <!-- Conversation Container -->
    <div class="conversation-container">
      <!-- Messages Loop -->
      <div v-for="(msg, index) in messages" :key="index" :class="msg.type">
        <div class="avatar" v-if="msg.type === 'user-message'">
          <!-- User Message Content -->
          <div class="message-content user-message-content">
            <div v-html="md.render(msg.content)"></div>
          </div>
          <!-- User Avatar -->
          <div class="avatar-icon user-avatar">
            :<svg-icon icon-class="user" />
          </div>
        </div>
        <div class="avatar" v-else>
          <!-- System Avatar -->
          <div class="avatar-icon system-avatar">
            <svg-icon icon-class="assistant" />:
          </div>
          <!-- System Message Content -->
          <div class="message-content system-message-content">
            <div v-html="md.render(msg.content)"></div>
          </div>
        </div>
      </div>
    </div>

    <!-- Input Field for User's Question with Welcome Message -->
    <div class="question-container">
      <div class="welcome-message-input">
        <el-input v-model="question" type="textarea" placeholder="请输入您的问题" />
      </div>
    </div>

    <!-- Send Button -->
    <el-button @click="sendChatMessage" type="primary">发送</el-button>
  </div>
</template>

<script setup>
import { historyList } from "@/api/system/chat";
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { getToken } from '@/utils/auth';
import { ref, reactive, onUnmounted } from 'vue';
import { onMounted } from 'vue';
import { md, initClipboard } from '@/utils/markdownSetup';

const baseURL = import.meta.env.VITE_APP_BASE_API;
const question = ref('');
const messages = ref([]);
const controller = new AbortController();
const toolCallId = ref(''); // 存储 toolCallId

const data = reactive({
  queryParams: {
    pageNum: 1,
    pageSize: 3,
  }
});

// 获取历史对话
async function gethistoryList() {
  const response = await historyList(data.queryParams);
  if (response.code === 200) {
    response.rows.forEach(item => {
      // 添加用户提问到messages中
      messages.value.push({
        type: 'user-message',
        content: item.question,
        timestamp: new Date(item.createTime).toLocaleString(),
        isHistory: true // 标记为历史记录
      });

      // 添加系统回复到messages中
      messages.value.push({
        type: 'system-message',
        content: item.answer,
        timestamp: new Date(item.createTime).toLocaleString(),
        isHistory: true // 标记为历史记录
      });
    });
  }
}

function sendChatMessage() {
  const signal = controller.signal;

  // 添加用户提问到messages中
  messages.value.push({
    type: 'user-message',
    content: question.value,
    timestamp: getCurrentTime()
  });

  let systemReply = '';

  fetchEventSource(`${baseURL}/system/chat/getChat`, {
    method: 'POST',
    body: JSON.stringify({ question: question.value, sessionId: toolCallId.value }), // 使用 toolCallId
    headers: {
      'Authorization': 'Bearer ' + getToken(),
      'Content-Type': 'application/json'
    },
    signal,
    onopen() { },
    onerror(event) { },
    onmessage(event) {
      const data = JSON.parse(event.data);
      const content = data.output.choices[0].message.content;

      systemReply += content;

      // 实时更新系统消息
      const lastSystemMessageIndex = messages.value.findIndex(msg => msg.type === 'system-message' && !msg.complete && !msg.isHistory);
      if (lastSystemMessageIndex !== -1) {
        messages.value[lastSystemMessageIndex].content = systemReply;
        messages.value[lastSystemMessageIndex].timestamp = getCurrentTime();
      } else {
        messages.value.push({
          type: 'system-message',
          content: systemReply,
          complete: false,
          timestamp: getCurrentTime()
        });
      }

      // 更新 toolCallId
      toolCallId.value = data.output.choices[0].message.toolCallId;

      // 自动滚动到底部
      scrollToBottom();
    },
    onclose() {
      // 标记最后一条系统消息为完成
      const lastSystemMessageIndex = messages.value.findIndex(msg => msg.type === 'system-message' && !msg.complete && !msg.isHistory);
      if (lastSystemMessageIndex !== -1) {
        messages.value[lastSystemMessageIndex].complete = true;
      }
    }
  });

  // 清空输入框
  question.value = '';
};

// 渲染Markdown内容
const renderMarkdown = (content) => {
  return md.render(content, 'java');
};

// 组件销毁前关闭EventSource连接
onUnmounted(() => {
  controller.abort();
});

// 滚动到底部函数
function scrollToBottom() {
  const container = document.querySelector('.conversation-container');
  if (container) {
    container.scrollTop = container.scrollHeight;
  }
};

// 获取当前时间
function getCurrentTime() {
  const now = new Date();
  return `${now.getHours()}:${now.getMinutes()} ${now.getHours() >= 12 ? 'PM' : 'AM'}`;
};

onMounted(() => {
  initClipboard(); // 初始化Clipboard.js
});
gethistoryList()
</script>

<style scoped>
.welcome-message {
  margin: 20px 0;
  text-align: center;
}

.question-container {
  text-align: center;
}

.welcome-message-input {
  margin-bottom: 10px;
}

.user-message,
.system-message {
  display: flex;
}

.user-message .avatar,
.system-message .avatar {
  display: flex;
}

.user-message .message-content,
.system-message .message-content {
  padding: 1px 5px;
  /* 调整内边距以提升视觉效果 */
  border-radius: 5px;
  /* 圆角边框 */
  display: inline-flex;
  /* 使用inline-flex以支持内容自适应并保持内部元素的对齐 */
  justify-content: center;
  /* 水平居中显示内部元素 */
  align-items: center;
  /* 垂直居中显示内部元素 */
  background-color: #f2f2f2;
  /* 用户消息背景色 */
  min-width: 70px;
  /* 最小宽度设置为70px,确保短消息不会显示得太窄 */
  max-width: 60%;
}

.system-message .message-content {
  background-color: #e6f7ff;
}

.user-message {
  justify-content: flex-end;
  /* 用户消息右对齐 */
}

.system-message {
  justify-content: flex-start;
  /* 系统消息左对齐 */
}

.copy-btn:hover {
  background-color: #303f9f;
  /* 鼠标悬停时颜色变化 */
}

.hljs {
  position: relative;
}

.hljs code {
  display: block;
  padding: 1em;
}

.code-block {
  position: relative;
}

.copy-btn {
  display: flex;
  align-items: center;
  cursor: pointer;
}

.copy-btn svg {
  fill: currentColor;
  width: 1em;
  height: 1em;
}
</style>

fetchEventSource函数释义:这段代码是一个事件源的实现,用于向指定URL发送POST请求获取聊天内容

  1. fetchEventSource函数:调用fetchEventSource函数来发送POST请求到${baseURL}/system/chat/getChat,并传递必要的参数。在请求中包括问题(question)和会话ID(sessionId)。
  2. Headers:设置请求头部,包括Authorization和Content-Type。Authorization使用Bearer加上getToken()函数返回的令牌,Content-Type设置为application/json。
  3. Signal:传递信号(signal)以便控制请求的终止。
  4. onopen()、onerror(event)、onmessage(event)、onclose():定义了不同事件发生时的处理函数。其中,onmessage处理从服务端返回的数据,解析JSON数据中的内容(content),更新系统回复(systemReply),更新消息列表(messages),更新工具调用ID(toolCallId),并自动滚动到底部。onclose用于标记最后一条系统消息为已完成。
  5. 清空输入框:在请求发送后,将输入框中的内容清空,以便用户继续输入新问题。

通过不断向服务器发送请求获取系统回复,并将回复展示在页面上。

总结

至此个人项目的简单接入AI大模型就告一段落,其中对于流式的输出与响应让博主花了一点时间,归根到底还是技术不够扎实,等博主在深耕一下前端技术领域,在回来更新样式和交互。

如何学习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%免费】🆓

在这里插入图片描述

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值