| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /*
- * @Author: ysh
- * @Date: 2025-07-08 16:43:22
- * @LastEditors: Please set LastEditors
- * @LastEditTime: 2025-07-16 15:49:45
- */
- import request from '@/utils/request'
- import { getToken } from '@/utils/auth'
-
- // 查询cmc聊天记录列表
- export function getAnswer(question, collectionName) {
- return request({
- url: '/llm/rag/answer',
- method: 'get',
- params: { question, collectionName }
- })
- }
-
- // 查询上下文引用文件
- export function getContextFile(question, collectionName) {
- return request({
- url: '/llm/rag/context',
- method: 'get',
- params: { question, collectionName }
- })
- }
-
- // 流式回答API - 使用fetch API处理流式响应
- export function getAnswerStream(question, collectionName, onMessage, onError, onComplete) {
- const baseURL = process.env.VUE_APP_BASE_API
- const url = `${baseURL}/llm/rag/answer?question=${encodeURIComponent(question)}&collectionName=${encodeURIComponent(collectionName)}`
-
- const controller = new AbortController()
-
- fetch(url, {
- method: 'GET',
- headers: {
- 'Authorization': 'Bearer ' + getToken(),
- 'Accept': 'application/json, text/event-stream',
- 'Cache-Control': 'no-cache'
- },
- signal: controller.signal
- }).then(response => {
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`)
- }
-
- const reader = response.body.getReader()
- const decoder = new TextDecoder()
- let buffer = ''
-
- function readStream() {
- return reader.read().then(({ done, value }) => {
- if (done) {
- console.log('=== 流式读取完成 ===')
- // 处理缓冲区中剩余的数据
- if (buffer.trim()) {
- console.log('=== 处理剩余缓冲区数据 ===', buffer)
- const lines = buffer.split(/\r?\n/)
- lines.forEach(line => {
- line = line.trim()
- if (!line || line.startsWith(':')) return
-
- console.log('处理剩余数据行:', line)
-
- // 尝试提取JSON数据
- let jsonData = null
-
- if (line.startsWith('data: ')) {
- try {
- jsonData = JSON.parse(line.slice(6))
- console.log('解析的剩余SSE数据:', jsonData)
- } catch (error) {
- console.error('解析剩余SSE数据失败:', error, line)
- }
- } else if (line.startsWith('data:')) {
- try {
- jsonData = JSON.parse(line.slice(5))
- console.log('解析的剩余SSE数据(无空格):', jsonData)
- } catch (error) {
- console.error('解析剩余SSE数据失败(无空格):', error, line)
- }
- } else {
- try {
- jsonData = JSON.parse(line)
- console.log('解析的剩余JSON数据:', jsonData)
- } catch (error) {
- console.error('解析剩余JSON数据失败:', error, line)
- }
- }
-
- // 处理解析成功的数据
- if (jsonData) {
- console.log('=== 解析成功的剩余数据 ===', jsonData)
-
- if (jsonData.resultContent) {
- console.log('=== 准备发送剩余resultContent ===', jsonData.resultContent)
- onMessage(jsonData.resultContent)
- } else if (jsonData.choices && jsonData.choices[0] && jsonData.choices[0].delta && jsonData.choices[0].delta.content) {
- console.log('=== 准备发送剩余OpenAI格式内容 ===', jsonData.choices[0].delta.content)
- onMessage(jsonData.choices[0].delta.content)
- } else if (typeof jsonData === 'string') {
- console.log('=== 准备发送剩余字符串 ===', jsonData)
- onMessage(jsonData)
- } else {
- console.log('=== 剩余数据格式不匹配,跳过content字段 ===', jsonData)
- }
- }
- })
- }
-
- onComplete()
- return
- }
-
- const chunk = decoder.decode(value, { stream: true })
- console.log('接收到原始数据块:', chunk)
- buffer += chunk
-
- // 处理可能包含\r\n的情况
- const lines = buffer.split(/\r?\n/)
-
- // 保留最后一行,因为它可能不完整
- buffer = lines.pop() || ''
-
- console.log('处理的行数:', lines.length)
- lines.forEach(line => {
- line = line.trim()
- if (!line || line.startsWith(':')) return
-
- console.log('处理数据行:', line)
-
- // 尝试提取JSON数据
- let jsonData = null
-
- if (line.startsWith('data: ')) {
- try {
- jsonData = JSON.parse(line.slice(6))
- console.log('解析的SSE数据:', jsonData)
- } catch (error) {
- console.error('解析SSE数据失败:', error, line)
- }
- } else if (line.startsWith('data:')) {
- try {
- jsonData = JSON.parse(line.slice(5))
- console.log('解析的SSE数据(无空格):', jsonData)
- } catch (error) {
- console.error('解析SSE数据失败(无空格):', error, line)
- }
- } else {
- try {
- jsonData = JSON.parse(line)
- console.log('解析的JSON数据:', jsonData)
- } catch (error) {
- console.error('解析JSON数据失败:', error, line)
- }
- }
-
- // 处理解析成功的数据
- if (jsonData) {
- console.log('=== 解析成功的数据 ===', jsonData)
-
- if (jsonData.resultContent) {
- console.log('=== 准备发送resultContent ===', jsonData.resultContent)
- onMessage(jsonData.resultContent)
- } else if (jsonData.choices && jsonData.choices[0] && jsonData.choices[0].delta && jsonData.choices[0].delta.content) {
- console.log('=== 准备发送OpenAI格式内容 ===', jsonData.choices[0].delta.content)
- onMessage(jsonData.choices[0].delta.content)
- } else if (typeof jsonData === 'string') {
- console.log('=== 准备发送字符串 ===', jsonData)
- onMessage(jsonData)
- } else {
- console.log('=== 数据格式不匹配,跳过content字段 ===', jsonData)
- }
- }
- })
-
- return readStream()
- })
- }
-
- return readStream()
- })
- .catch(error => {
- if (error.name === 'AbortError') {
- console.log('请求被取消')
- return
- }
- console.error('流式请求错误:', error)
- onError(new Error('网络连接失败,请检查网络连接后重试'))
- })
-
- // 返回controller以便外部可以取消请求
- return controller
- }
|