import axios, { cancelToken } from '@/services/config' import { v4 as uuidv4 } from 'uuid' import { fetchEventSource } from '@microsoft/fetch-event-source' import { ref } from 'vue' const model = {} let organizeId = '' const userId2 = ref('') const userName = ref('') interface ChatParams { id: string; message: string; userId: string; model: string; file_ids: string[]; sound_url: string; temperature: number; top_p: number; max_completion_tokens: number; stream: boolean; uid: string; session_name: string; tts_language: string; } const DEFAULT_PARAMS: Omit = { id: 'a7741704-ba56-40b7-a6b8-62a423ef9376', userId: '6c56ec0e-2c74-11ef-bee5-005056b86db5', model: 'open-doubao', file_ids: [], sound_url: '', temperature: 0.2, top_p: 1, max_completion_tokens: 4096, session_name: 'pptSession_name', tts_language: 'zh-CN' } export const chat_no_stream = (msg: string, agentId: string, userId: string, language: string, session_name?: string): { promise: Promise; abort: () => void } => { const source = cancelToken.source() const promise = (async () => { const agentData = await getAgentModel(agentId) const params: ChatParams = { ...DEFAULT_PARAMS, id: agentId, message: `Language: ${language === 'en' ? 'English' : language === 'hk' ? 'Traditional Chinese' : 'Chinese' } ${msg} ${language === 'hk' ? '請用繁體中文回复' : language === 'en' ? 'Please reply in English' : '请用中文回复'}`, uid: uuidv4(), stream: false, model: agentData?.modelType || 'open-doubao', userId: userId, tts_language: getTtsLanguage(language), session_name: session_name || uuidv4() } try { const res = await axios.post('https://appapi.cocorobo.cn/api/agentchats/ai_agent_chat', params, { cancelToken: source.token }) let content = res?.message || '' console.log(content) // 清理可能的 markdown 格式 if (content.includes('```json')) { // 提取 ```json 和 ``` 之间的内容 const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/) if (jsonMatch) { content = jsonMatch[1].trim() } } else if (content.includes('```')) { // 提取 ``` 和 ``` 之间的内容 const codeMatch = content.match(/```\s*([\s\S]*?)\s*```/) if (codeMatch) { content = codeMatch[1].trim() } } return content } catch (error) { console.log(error) return '' } })() return { promise, abort: () => source.cancel('Request canceled by user') } } export const chat_stream = async ( msg: string, agentId: string, userId: string, language: string, onMessage: (event: { type: 'message' | 'close' | 'error' | 'messageEnd'; data: string }) => void, session_name?: string, file_ids?: Array, model?: string ): Promise<{ abort: () => void }> => { const agentData = await getAgentModel(agentId) const params: ChatParams = { ...DEFAULT_PARAMS, id: agentId, file_ids: file_ids || [], message: `Language: ${language === 'en' ? 'English' : language === 'hk' ? 'Traditional Chinese' : 'Chinese' } ${msg} ${language === 'hk' ? '請用繁體中文回复' : language === 'en' ? 'Please reply in English' : '请用中文回复'}`, uid: uuidv4(), stream: true, model: model || agentData?.modelType || 'open-doubao', userId: userId, tts_language: getTtsLanguage(language), session_name: session_name || uuidv4() } const ctrl = new AbortController() let content = '' // 开始请求 fetchEventSource('https://appapi.cocorobo.cn/api/agentchats/ai_agent_chat', { method: 'POST', body: JSON.stringify(params), signal: ctrl.signal, headers: { 'Content-Type': 'application/json', }, onmessage(event) { const data = JSON.parse(event.data) if (data.content) { if (data.content != '[DONE]') { content += data.content onMessage({ type: 'message', data: content }) } else { onMessage({ type: 'messageEnd', data: content }) } } }, onclose() { onMessage({ type: 'close', data: 'SSE Connection closed' }) }, onerror(err) { onMessage({ type: 'error', data: err.message || 'Unknown error' }) // 返回 undefined 以阻止自动重连,如需重连则删除此行 throw err }, }).catch(err => { onMessage({ type: 'error', data: err || 'Unknown error' }) console.log('err', err) }) // 返回 abort 方法 return { abort: () => ctrl.abort() } } export const getAgentModel = async (agentId: string) => { if (model[agentId]) { return model[agentId] } const res = await axios.get(`https://appapi.cocorobo.cn/api/agents/agent/${agentId}`) model[agentId] = res return model[agentId] } export const getTtsLanguage = (langCode: string) => { switch (langCode) { case 'en':return 'en-US' case 'hk':return 'yue-CN' default :return 'zh-CN' } } // AI 模型常量 const AI_MODEL_CONSTANTS = { // DEFAULT_MODEL: 'gpt-4o-2024-11-20' DEFAULT_MODEL: 'qwen-flash' } export const chat_no_stream2 = async (prompt: any[] = [], response_format = { 'type': 'text' }, model = AI_MODEL_CONSTANTS.DEFAULT_MODEL) => { return await new Promise((resolve) => { const uid = uuidv4() const data = JSON.stringify({ model: model, temperature: 0, max_tokens: 4096, top_p: 1, frequency_penalty: 0, presence_penalty: 0, messages: prompt, uid: uid, mind_map_question: '', stream: false, response_format: response_format }) const config = { method: 'post', url: 'https://appapi.cocorobo.cn/api/common/chat', headers: { 'Content-Type': 'application/json' }, data: data, } axios(config) .then((response) => { let content = response?.FunctionResponse?.choices[0]?.message?.content || '' // 清理可能的 markdown 格式 if (content.includes('```json')) { // 提取 ```json 和 ``` 之间的内容 const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/) if (jsonMatch) { content = jsonMatch[1].trim() } } else if (content.includes('```')) { // 提取 ``` 和 ``` 之间的内容 const codeMatch = content.match(/```\s*([\s\S]*?)\s*```/) if (codeMatch) { content = codeMatch[1].trim() } } resolve(content) }) .catch( (error) => { console.log(error) // this.$message.error('服务器繁忙'); resolve(false) }) }) } export const agentlistloading = ref(false) export const getAgentChatList = async (id: string, userId: string): Promise => { if (!id) { return [] } agentlistloading.value = true if (!organizeId || userId2.value !== userId) { userId2.value = userId const res = await axios.get('https://pbl.cocorobo.cn/api/pbl/selectUser', { params: { userid: userId } }) userName.value = res[0][0].name organizeId = res[0][0].organizeId } try { const response = await axios.post('https://gpt4.cocorobo.cn/get_agent_chat', { userid: userId, groupid: id, }, { headers: { 'Content-Type': 'application/json', 'hwMac': organizeId, }, }) const chat_list = JSON.parse(response?.FunctionResponse || '[]') const messages = [] chat_list.forEach((item: any, index: number) => { const json: any = { role: 'user' as const, userName: item.username, content: decodeURIComponent(item.problem), uid: id, AI: 'AI', aiContent: decodeURIComponent(item.answer), reasoning: item.reasoning_content, oldContent: decodeURIComponent(new DOMParser().parseFromString( item.answer, 'text/html' ).documentElement.textContent), isShowSynchronization: false, filename: item.filename, index: index, createtime: item.createtime, is_mind_map: item.problem.includes('思维导图') || item.problem.includes('思維導圖') || item.problem.includes('mindMap'), graph: item.problem === '知识图谱', // 使用默认值,因为无法访问this.lang } try { json.jsonData = item.jsonData !== 'undefined' && item.jsonData !== null ? JSON.parse(decodeURIComponent(item.jsonData)) : null // 从 jsonData 中读取 syncTranscriptionText 值 if (json.jsonData && json.jsonData.syncTranscriptionText !== undefined) { json.syncTranscriptionText = json.jsonData.syncTranscriptionText } else { // 如果没有 jsonData 或 syncTranscriptionText,使用默认值 json.syncTranscriptionText = false } // 从 jsonData 中读取 contentType 值 if (json.jsonData && json.jsonData.contentType !== undefined) { json.contentType = json.jsonData.contentType } else { // 如果没有 jsonData 或 contentType,使用默认值 json.contentType = 'text' } // 新增:从 jsonData 中恢复用户音频播放所需字段 if (json.jsonData && json.jsonData.audio) { json.audio = json.jsonData.audio } if (json.jsonData && json.jsonData.durationSec) { json.durationSec = json.jsonData.durationSec } } catch (error) { console.error('Error parsing jsonData:', error) json.jsonData = null json.syncTranscriptionText = false json.contentType = 'text' agentlistloading.value = false } messages.push(json) }) agentlistloading.value = false return messages } catch (error) { console.error('Error fetching agent chat list:', error) return [] } } export interface InsertChatParams { answer: string; problem: string; type: string; alltext: string; assistant_id: string; userId: string; userName: string; fileId?: string; latestMessage?: any; agentHeadUrl?: string; agentAssistantName?: string; jsonData?: any; } export interface InsertChatResult { success: boolean; questions?: string[]; } export const insertChat = async (params: InsertChatParams): Promise => { const { answer, problem, type, alltext, assistant_id, fileId, latestMessage, agentHeadUrl, agentAssistantName, jsonData } = params const jsonData2: any = { headUrl: agentHeadUrl || '', assistantName: agentAssistantName || '', ...jsonData } try { const response = await axios.post('https://gpt4.cocorobo.cn/insert_chat', { userId: userId2.value, userName: userName.value, groupId: assistant_id, answer: encodeURIComponent(answer), problem: encodeURIComponent(problem), file_id: type === 'chat' ? '' : fileId, alltext, type, jsonData: encodeURIComponent(JSON.stringify(jsonData)) }, { headers: { 'Content-Type': 'application/json', hwMac: organizeId, }, }) // 处理返回的问题结果 if (response?.FunctionResponse?.questions_result) { const data = response?.FunctionResponse.questions_result if (data.includes('\n')) { const arr = data.split('\n') let questions: string[] = [] if (arr.length > 3) { questions = arr.slice(0, 3) } else { questions = [...arr] } return { success: true, questions } } } return { success: true } } catch (error) { console.error('Error inserting chat:', error) return { success: false } } }