chat.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <template>
  2. <div>
  3. <div class="content-box">
  4. <pre>{{ streamData }}</pre>
  5. <span class="dot"></span>
  6. <span class="dot"></span>
  7. </div>
  8. <el-button @click="stopMessage">停止回答</el-button>
  9. </div>
  10. </template>
  11. <script setup>
  12. import {getAiChatRecordList} from '@/api/xjc-integratedmachine/common/aiChat.js'
  13. import { getToken } from '@/utils/auth'
  14. let data = ref()
  15. const streamData = ref(''); // 存储流式数据
  16. const isLoading = ref(false); // 加载状态
  17. let reader = null; // 读取器实例
  18. let controller = null; // AbortController用于中止请求
  19. // 查看所有聊天记录
  20. list();
  21. function list() {
  22. getAiChatRecordList().then(resp =>{
  23. console.log(resp)
  24. data.value = resp;
  25. })
  26. }
  27. const sendMessage = async() => {
  28. try{
  29. isLoading.value = true;
  30. streamData.value = ''; // 清空之前的数据
  31. // 创建AbortController以便可以中止请求
  32. controller = new AbortController();
  33. // 请求体
  34. let form = {
  35. "content": "你是谁?"
  36. }
  37. // 发送fetch请求
  38. const response = await fetch('/dev-api/ai/chat/stream', {
  39. method: 'POST',
  40. headers: {
  41. 'Content-Type': 'application/json',
  42. 'Authorization': 'Bearer ' + getToken()
  43. },
  44. body: JSON.stringify(form)
  45. });
  46. // 获取可读流的读取器
  47. reader = response.body.getReader();
  48. const decoder = new TextDecoder('utf-8');
  49. // 循环读取流数据
  50. while (true) {
  51. const { done, value } = await reader.read();
  52. if (done) break; // 如果流读取完成则退出循环
  53. // 解码并追加数据
  54. let chunk = decoder.decode(value, { stream: true });
  55. chunk = chunk.replace(/\n/g, '').replace(/data:/g, '')
  56. streamData.value += chunk;
  57. }
  58. }catch (error) {
  59. // 如果是手动中止,不显示错误
  60. if (error.name !== 'AbortError') {
  61. console.error('流式读取失败:', error);
  62. streamData.value = 'Error: ' + error.message;
  63. }
  64. } finally {
  65. isLoading.value = false;
  66. }
  67. }
  68. const stopMessage = () => {
  69. if (reader) {
  70. // 取消读取
  71. reader.cancel().catch(() => {});
  72. reader = null;
  73. }
  74. if (controller) {
  75. // 中止请求
  76. controller.abort();
  77. controller = null;
  78. }
  79. isLoading.value = false;
  80. }
  81. onMounted(()=>{
  82. sendMessage()
  83. })
  84. </script>
  85. <script>
  86. export default {
  87. name: "chat"
  88. }
  89. </script>
  90. <style scoped>
  91. .content-box {
  92. max-height: 300px;
  93. overflow-y: auto;
  94. border: 1px solid #eee;
  95. padding: 10px;
  96. margin-top: 10px;
  97. background: #f9f9f9;
  98. }
  99. pre {
  100. white-space: pre-wrap;
  101. word-wrap: break-word;
  102. }
  103. .dot {
  104. display: inline-block;
  105. margin-left: 5px;
  106. width: 8px;
  107. height: 8px;
  108. background-color: #000000;
  109. border-radius: 50%;
  110. animation: pulse 1.2s infinite ease-in-out both;
  111. }
  112. </style>