综合办公系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rag.js 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * @Author: ysh
  3. * @Date: 2025-07-08 16:43:22
  4. * @LastEditors: Please set LastEditors
  5. * @LastEditTime: 2025-07-16 15:49:45
  6. */
  7. import request from '@/utils/request'
  8. import { getToken } from '@/utils/auth'
  9. // 查询cmc聊天记录列表
  10. export function getAnswer(question, collectionName) {
  11. return request({
  12. url: '/llm/rag/answer',
  13. method: 'get',
  14. params: { question, collectionName }
  15. })
  16. }
  17. // 查询上下文引用文件
  18. export function getContextFile(question, collectionName) {
  19. return request({
  20. url: '/llm/rag/context',
  21. method: 'get',
  22. params: { question, collectionName }
  23. })
  24. }
  25. // 流式回答API - 使用fetch API处理流式响应
  26. export function getAnswerStream(question, collectionName, onMessage, onError, onComplete) {
  27. const baseURL = process.env.VUE_APP_BASE_API
  28. const url = `${baseURL}/llm/rag/answer?question=${encodeURIComponent(question)}&collectionName=${encodeURIComponent(collectionName)}`
  29. const controller = new AbortController()
  30. fetch(url, {
  31. method: 'GET',
  32. headers: {
  33. 'Authorization': 'Bearer ' + getToken(),
  34. 'Accept': 'application/json, text/event-stream',
  35. 'Cache-Control': 'no-cache'
  36. },
  37. signal: controller.signal
  38. }).then(response => {
  39. if (!response.ok) {
  40. throw new Error(`HTTP error! status: ${response.status}`)
  41. }
  42. const reader = response.body.getReader()
  43. const decoder = new TextDecoder()
  44. let buffer = ''
  45. function readStream() {
  46. return reader.read().then(({ done, value }) => {
  47. if (done) {
  48. console.log('=== 流式读取完成 ===')
  49. // 处理缓冲区中剩余的数据
  50. if (buffer.trim()) {
  51. console.log('=== 处理剩余缓冲区数据 ===', buffer)
  52. const lines = buffer.split(/\r?\n/)
  53. lines.forEach(line => {
  54. line = line.trim()
  55. if (!line || line.startsWith(':')) return
  56. console.log('处理剩余数据行:', line)
  57. // 尝试提取JSON数据
  58. let jsonData = null
  59. if (line.startsWith('data: ')) {
  60. try {
  61. jsonData = JSON.parse(line.slice(6))
  62. console.log('解析的剩余SSE数据:', jsonData)
  63. } catch (error) {
  64. console.error('解析剩余SSE数据失败:', error, line)
  65. }
  66. } else if (line.startsWith('data:')) {
  67. try {
  68. jsonData = JSON.parse(line.slice(5))
  69. console.log('解析的剩余SSE数据(无空格):', jsonData)
  70. } catch (error) {
  71. console.error('解析剩余SSE数据失败(无空格):', error, line)
  72. }
  73. } else {
  74. try {
  75. jsonData = JSON.parse(line)
  76. console.log('解析的剩余JSON数据:', jsonData)
  77. } catch (error) {
  78. console.error('解析剩余JSON数据失败:', error, line)
  79. }
  80. }
  81. // 处理解析成功的数据
  82. if (jsonData) {
  83. console.log('=== 解析成功的剩余数据 ===', jsonData)
  84. if (jsonData.resultContent) {
  85. console.log('=== 准备发送剩余resultContent ===', jsonData.resultContent)
  86. onMessage(jsonData.resultContent)
  87. } else if (jsonData.choices && jsonData.choices[0] && jsonData.choices[0].delta && jsonData.choices[0].delta.content) {
  88. console.log('=== 准备发送剩余OpenAI格式内容 ===', jsonData.choices[0].delta.content)
  89. onMessage(jsonData.choices[0].delta.content)
  90. } else if (typeof jsonData === 'string') {
  91. console.log('=== 准备发送剩余字符串 ===', jsonData)
  92. onMessage(jsonData)
  93. } else {
  94. console.log('=== 剩余数据格式不匹配,跳过content字段 ===', jsonData)
  95. }
  96. }
  97. })
  98. }
  99. onComplete()
  100. return
  101. }
  102. const chunk = decoder.decode(value, { stream: true })
  103. console.log('接收到原始数据块:', chunk)
  104. buffer += chunk
  105. // 处理可能包含\r\n的情况
  106. const lines = buffer.split(/\r?\n/)
  107. // 保留最后一行,因为它可能不完整
  108. buffer = lines.pop() || ''
  109. console.log('处理的行数:', lines.length)
  110. lines.forEach(line => {
  111. line = line.trim()
  112. if (!line || line.startsWith(':')) return
  113. console.log('处理数据行:', line)
  114. // 尝试提取JSON数据
  115. let jsonData = null
  116. if (line.startsWith('data: ')) {
  117. try {
  118. jsonData = JSON.parse(line.slice(6))
  119. console.log('解析的SSE数据:', jsonData)
  120. } catch (error) {
  121. console.error('解析SSE数据失败:', error, line)
  122. }
  123. } else if (line.startsWith('data:')) {
  124. try {
  125. jsonData = JSON.parse(line.slice(5))
  126. console.log('解析的SSE数据(无空格):', jsonData)
  127. } catch (error) {
  128. console.error('解析SSE数据失败(无空格):', error, line)
  129. }
  130. } else {
  131. try {
  132. jsonData = JSON.parse(line)
  133. console.log('解析的JSON数据:', jsonData)
  134. } catch (error) {
  135. console.error('解析JSON数据失败:', error, line)
  136. }
  137. }
  138. // 处理解析成功的数据
  139. if (jsonData) {
  140. console.log('=== 解析成功的数据 ===', jsonData)
  141. if (jsonData.resultContent) {
  142. console.log('=== 准备发送resultContent ===', jsonData.resultContent)
  143. onMessage(jsonData.resultContent)
  144. } else if (jsonData.choices && jsonData.choices[0] && jsonData.choices[0].delta && jsonData.choices[0].delta.content) {
  145. console.log('=== 准备发送OpenAI格式内容 ===', jsonData.choices[0].delta.content)
  146. onMessage(jsonData.choices[0].delta.content)
  147. } else if (typeof jsonData === 'string') {
  148. console.log('=== 准备发送字符串 ===', jsonData)
  149. onMessage(jsonData)
  150. } else {
  151. console.log('=== 数据格式不匹配,跳过content字段 ===', jsonData)
  152. }
  153. }
  154. })
  155. return readStream()
  156. })
  157. }
  158. return readStream()
  159. })
  160. .catch(error => {
  161. if (error.name === 'AbortError') {
  162. console.log('请求被取消')
  163. return
  164. }
  165. console.error('流式请求错误:', error)
  166. onError(new Error('网络连接失败,请检查网络连接后重试'))
  167. })
  168. // 返回controller以便外部可以取消请求
  169. return controller
  170. }