当前位置:   article > 正文

vue3+质谱AI实现仿chatgbt聊天响应数据加载(原创)_vue实现仿chatgpt聊天页面

vue实现仿chatgpt聊天页面

最终代码在最下方,只是一个demo,欢迎指正,谢谢。

一、获取质谱AI的API密钥

登录注册的过程很简单,这里不再进行讲述,节省大家的时间(官网:https://open.bigmodel.cn/ )。进入首页后会赠送资源包,资源包可以用来免费调用质谱AI的gbt模型。在页面的右上角可以获取到API密钥。如图

二、利用fetch发送请求

参考官方文档https://open.bigmodel.cn/dev/api#http_para

官方文档利用http做请求,需要携带 API Key发送请求,就可以获得AI模型返回的数据。这里我们用fetch来实现(为什么不用axios后面会说明),代码示例如下:

  1. const response = await fetch('https://open.bigmodel.cn/api/paas/v4/chat/completions', {
  2. method: 'POST',
  3. headers: {
  4. 'Authorization': `Bearer ${apiKey}`,
  5. 'Content-Type': 'application/json'
  6. },
  7. body: JSON.stringify(data)
  8. });
  9. //传入的data数据
  10. const data = {
  11. model: "glm-4",
  12. messages: [
  13. {
  14. role: "user",
  15. content: inputValue.value
  16. }
  17. ]
  18. };

返回数据的大概格式如下

在choices里面可以获取到AI模型返回的字符串。

三、构建简单的聊天页面,实现AI回复功能

构建一个简单的聊天页面,利用@click获取到用户输入框的内容并且发送请求,效果如下

这个时候发现了一个问题,在质谱AI在返回数据的时候,是将整个响应的数据都返回的,但是chatgbt是类似于实时回答的数据流展示,如何实现这个效果呢,查阅官方文档,我发现在智谱AI开放平台里面有一段参数描述 

我将stream设置为true,再次发送请求

  1. const data = {
  2. model: "glm-4",
  3. messages: [
  4. {
  5. role: "user",
  6. content: inputValue.value
  7. }
  8. ],
  9. stream: true
  10. };

获取到的数据格式如下:

我们需要使用 ReadableStreamreader 读取流数据,并使用 TextDecoder 解码文本。逐行处理流数据,解析 JSON 并将内容推入 messages 数组。之所以不用axios,是因为axiosresponse.data 默认是一个 JavaScript 对象,而不是一个 ReadableStream。这样,就可以拿到每次推流的数据,通过修改messgae数组内的子项的内容,来实现一个加载文字的效果。

全部代码如下,如果对你有帮助,请帮我点一个赞,谢谢!:

  1. <template>
  2. <div class="chat-container">
  3. <div class="chat-display">
  4. <div class="msg" v-for="(msg, index) in messages" :key="index"><pre style="display: block;">{{ msg }}</pre></div>
  5. </div>
  6. <div class="chat-input">
  7. <input type="text" placeholder="请输入内容" v-model="inputValue">
  8. <button @click="sendMessage">发送</button>
  9. </div>
  10. </div>
  11. </template>
  12. <script setup>
  13. import { ref } from 'vue';
  14. import axios from 'axios';
  15. const apiKey = ''; // 替换为你的 API Key
  16. const inputValue = ref('');
  17. const messages = ref([]);
  18. const sendMessage = async () => {
  19. if (inputValue.value.trim() !== '') {
  20. const data = {
  21. model: "glm-4",
  22. messages: [
  23. {
  24. role: "user",
  25. content: inputValue.value
  26. }
  27. ],
  28. stream: true
  29. };
  30. try {
  31. const response = await fetch('https://open.bigmodel.cn/api/paas/v4/chat/completions', {
  32. method: 'POST',
  33. headers: {
  34. 'Authorization': `Bearer ${apiKey}`,
  35. 'Content-Type': 'application/json'
  36. },
  37. body: JSON.stringify(data)
  38. });
  39. messages.value.push(inputValue.value)
  40. let len=messages.value.length;
  41. if (!response.body) {
  42. throw new Error('Response has no body');
  43. }
  44. inputValue.value=''
  45. const reader = response.body.getReader();
  46. const decoder = new TextDecoder();
  47. let partialMessage = '';
  48. const processStream = async () => {
  49. let result;
  50. while (!(result = await reader.read()).done) {
  51. const text = decoder.decode(result.value, { stream: true });
  52. partialMessage += text;
  53. const lines = partialMessage.split('\n');
  54. partialMessage = lines.pop(); // 保留最后一个部分消息
  55. console.log(lines,',',partialMessage);
  56. lines.forEach(line => {
  57. if (line.startsWith('data: ')) {
  58. const json = line.replace('data: ', '');
  59. if (json === '[DONE]') {
  60. return;
  61. }
  62. try {
  63. const parsedData = JSON.parse(json);
  64. const content = parsedData.choices[0].delta.content;
  65. if(!messages.value[len]){
  66. messages.value[len]=''
  67. }
  68. messages.value[len]+=content
  69. console.log(messages);
  70. } catch (error) {
  71. console.error('解析 JSON 出错:', error);
  72. }
  73. }
  74. });
  75. }
  76. };
  77. processStream();
  78. } catch (error) {
  79. console.error('请求失败:', error);
  80. }
  81. }
  82. };
  83. </script>
  84. <style scoped>
  85. .chat-container {
  86. display: flex;
  87. flex-direction: column;
  88. align-items: center;
  89. width: 500px;
  90. }
  91. .chat-display {
  92. border: 1px solid #ccc;
  93. width: 500px;
  94. height: 300px;
  95. overflow-y: auto;
  96. margin-bottom: 10px;
  97. padding: 10px;
  98. }
  99. /* 隐藏滚动条 - Chrome, Safari 和 Opera */
  100. .chat-display::-webkit-scrollbar {
  101. display: none;
  102. }
  103. /* 隐藏滚动条 - Firefox */
  104. .chat-display {
  105. scrollbar-width: none; /* Firefox */
  106. }
  107. /* 隐藏滚动条 - IE 10+ */
  108. .chat-display {
  109. -ms-overflow-style: none; /* IE and Edge */
  110. }
  111. .chat-input {
  112. display: flex;
  113. }
  114. .chat-input input {
  115. flex: 1;
  116. padding: 10px;
  117. border: 1px solid #ccc;
  118. border-radius: 4px 0 0 4px;
  119. }
  120. .chat-input button {
  121. padding: 10px;
  122. border: 1px solid #ccc;
  123. border-radius: 0 4px 4px 0;
  124. background-color: #007bff;
  125. color: white;
  126. cursor: pointer;
  127. }
  128. .chat-input button:hover {
  129. background-color: #0056b3;
  130. }
  131. .msg{
  132. text-align: left;
  133. width: 100%;
  134. }
  135. pre{
  136. width: 500px;
  137. white-space: pre-wrap; /* 允许换行 */
  138. word-break: break-word; /* 超出宽度时换行 */
  139. overflow-wrap: break-word; /* 超出宽度时换行 */
  140. }
  141. </style>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/761300
推荐阅读
相关标签
  

闽ICP备14008679号