feat: 测试之后修改bug

This commit is contained in:
常东方 2025-06-09 17:38:54 +08:00
parent 81fb19092e
commit b1d2fd47c4
4 changed files with 218 additions and 135 deletions

View File

@ -52,6 +52,7 @@
"build:app-ios": "uni build -p app-ios", "build:app-ios": "uni build -p app-ios",
"build:custom": "uni build -p", "build:custom": "uni build -p",
"build:h5": "uni build", "build:h5": "uni build",
"build:h5-dev": "uni build --mode dev",
"build": "uni build", "build": "uni build",
"build:h5:ssr": "uni build --ssr", "build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay", "build:mp-alipay": "uni build -p mp-alipay",

View File

@ -160,7 +160,7 @@
v-for="(file, fileIdx) in msg.content" v-for="(file, fileIdx) in msg.content"
:key="fileIdx" :key="fileIdx"
style="flex: 0 0 6rem" style="flex: 0 0 6rem"
class="relative text-xs h-32 w-80 rounded-md overflow-hidden mr-1 c-black" class="relative text-xs h-32 rounded-md overflow-hidden mr-1 c-black"
> >
<!-- @click="previewVideo(msg.content)"--> <!-- @click="previewVideo(msg.content)"-->
<video <video
@ -184,11 +184,17 @@
</view> </view>
</view> </view>
<view <view
v-if="msg.role === 'assistant' && msg.type === 'text'" v-if="
msg.role === 'assistant' && msg.type === 'text' && messages.length - 1 === idx
"
class="absolute bottom--3.5 flex space-x-3 ml-1" class="absolute bottom--3.5 flex space-x-3 ml-1"
> >
<image src="/static/aichat/copy.png" class="w-4 h-4" @click="copyText(msg)" /> <image src="/static/aichat/copy.png" class="w-4 h-4" @click="copyText(msg)" />
<image src="/static/aichat/resect.png" class="w-4.3 h-4" @click="refreshText()" /> <image
src="/static/aichat/resect.png"
class="w-4.3 h-4"
@click="refreshText(msg)"
/>
</view> </view>
</view> </view>
<image <image
@ -332,6 +338,7 @@
@focus="onFocus" @focus="onFocus"
@confirm="sendText" @confirm="sendText"
placeholder="想对我说点什么~" placeholder="想对我说点什么~"
maxlength="5000"
class="flex-1 h-10 px-3 border border-gray-100 bg-[#f9f9f9] rounded-1 focus:outline-none" class="flex-1 h-10 px-3 border border-gray-100 bg-[#f9f9f9] rounded-1 focus:outline-none"
/> />
<!-- 将keyup替换为confirm --> <!-- 将keyup替换为confirm -->
@ -349,7 +356,6 @@
v-if="sendTextLoading && inputText.length <= 0" v-if="sendTextLoading && inputText.length <= 0"
src="/static/aichat/enter-no.png" src="/static/aichat/enter-no.png"
class="w-7 h-7" class="w-7 h-7"
@click="sendText()"
:disabled="loading" :disabled="loading"
:class="[knowledgeOpen ? 'ml-2' : 'ml-0']" :class="[knowledgeOpen ? 'ml-2' : 'ml-0']"
/> />
@ -477,6 +483,7 @@
import { ref, reactive, nextTick, watchEffect, watch } from 'vue' import { ref, reactive, nextTick, watchEffect, watch } from 'vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
// import store from '@/store'
import { getEnvBaseUrl } from '@/utils' import { getEnvBaseUrl } from '@/utils'
import guid from '@/utils/guid.js' import guid from '@/utils/guid.js'
import type { IGptRequestBody } from '@/service/index/foo' import type { IGptRequestBody } from '@/service/index/foo'
@ -489,15 +496,16 @@ import {
officeFileTypeList as fileType, officeFileTypeList as fileType,
videoFileType as videoType, videoFileType as videoType,
picFileType as picType, picFileType as picType,
isJsonObject,
} from './utils/index' } from './utils/index'
import 'dayjs/locale/zh-cn' import 'dayjs/locale/zh-cn'
import { showToastErr, showToastOk, time_format3 } from '@/utils/tools' import { showToastErr, showToastOk, time_format3 } from '@/utils/tools'
import { uploadFileChunk } from './utils/api.js' import { uploadFileChunk } from './utils/api.js'
// import { TOKEN, AVATAR } from './utils/test' // import { TOKEN, AVATAR } from './utils/test'
import { deepClone } from 'wot-design-uni/components/common/util' import { deepClone } from 'wot-design-uni/components/common/util'
import { log } from 'console'
dayjs.locale('zh-cn') dayjs.locale('zh-cn')
const store = useUserStore()
interface UploadFile { interface UploadFile {
id: string id: string
@ -605,7 +613,7 @@ async function createChatSession() {
gptModel: chatMode.value, gptModel: chatMode.value,
}, },
header: { header: {
Authorization: token.value, // Authorization: token.value,
}, },
}) })
// listUuid // listUuid
@ -627,9 +635,9 @@ const state = reactive({
}) })
const scrollTop = ref(0) const scrollTop = ref(0)
async function fetchHistoryList() { async function fetchHistoryList() {
// if(state.page*state.pageSize>state.total && state.total!==null){ if (state.page >= state.total / state.pageSize + 1 && state.total !== null) {
// return return
// } }
if (state.loading) { if (state.loading) {
return return
} }
@ -643,12 +651,18 @@ async function fetchHistoryList() {
pageSize: state.pageSize, pageSize: state.pageSize,
}, },
header: { header: {
Authorization: token.value, // Authorization: token.value,
}, },
}) })
if (resp.data && resp.data.data) { if (resp.data && resp.data.data) {
rawList.value = rawList.value.concat(resp.data.data.data) if (state.total === null) {
state.total = resp.data.data.count //Math.ceil(resp.data.count/state.page) rawList.value = resp.data.data.data
state.total = resp.data.data.count
} else {
rawList.value = rawList.value.concat(resp.data.data.data)
state.total = resp.data.data.count //Math.ceil(resp.data.count/state.page)
}
// scrollTop.value+=60; // scrollTop.value+=60;
} }
} catch (err) { } catch (err) {
@ -662,7 +676,10 @@ const scrolltolowerLoadData = (e) => {
} }
watch( watch(
() => state.page, () => state.page,
async () => { async (newval) => {
if (newval <= 0) {
return
}
await fetchHistoryList() await fetchHistoryList()
}, },
{ deep: true }, { deep: true },
@ -670,9 +687,12 @@ watch(
async function openPopup() { async function openPopup() {
state.page++ state.page++
showPopup.value = true showPopup.value = true
rawList.value = []
} }
function closePopup() { function closePopup() {
showPopup.value = false showPopup.value = false
state.page = 0
state.total = null
} }
function toggleFullscreen() { function toggleFullscreen() {
fullscreen.value = !fullscreen.value fullscreen.value = !fullscreen.value
@ -689,12 +709,12 @@ async function fetchHistoryDiets(value) {
gptModel: chatMode.value, gptModel: chatMode.value,
}, },
header: { header: {
Authorization: token.value, // Authorization: token.value,
}, },
}) })
if (resp && resp.data && resp.data.data) { if (resp && resp.data && resp.data.data) {
const rawList = resp.data.data.detail // const rawList = resp?.data?.data?.detail //
listUuid.value = resp.data.data.listUuid listUuid.value = resp?.data?.data?.listUuid
// const newMessages = parseBackendMessages(JSON.parse(rawList)) // const newMessages = parseBackendMessages(JSON.parse(rawList))
// //
messages.splice(0, messages.length, ...JSON.parse(rawList)) messages.splice(0, messages.length, ...JSON.parse(rawList))
@ -971,18 +991,30 @@ onMounted(async () => {
try { try {
const init = async () => { const init = async () => {
const wv = plus.webview.currentWebview() // Webview const wv = plus.webview.currentWebview() // Webview
token.value = wv.token || uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN token.value =
wv.token ||
uni.getStorageSync('token') ||
store.userInfo.token ||
import.meta.env.VITE_DEV_TOKEN
userInfo.value = JSON.parse(wv.userInfo) || {} userInfo.value = JSON.parse(wv.userInfo) || {}
refreshToken.value = wv.refreshToken || uni.getStorageSync('refreshToken') refreshToken.value = wv.refreshToken || uni.getStorageSync('refreshToken')
statusBarHeight.value = wv.statusBarHeight || uni.getSystemInfoSync().statusBarHeight statusBarHeight.value = wv.statusBarHeight || uni.getSystemInfoSync().statusBarHeight
userAvatar.value = userInfo.value.Avatar userAvatar.value = userInfo.value.Avatar
mask.value = userInfo.value.ID mask.value = userInfo.value.ID
store.setUserInfo({
token: token.value,
avatar: userInfo.value.Avatar,
refreshToken: refreshToken.value,
statusBarHeight: statusBarHeight.value,
})
await createChatSession() await createChatSession()
} }
init() init()
} catch (e) { } catch (e) {
console.error('onMounted e: ', e) console.error('onMounted e: ', e)
} finally { } finally {
token.value = store.userInfo.token
await createChatSession()
} }
}) })
@ -1411,12 +1443,60 @@ const onPickImage = () => {
}, },
}) })
} }
// Android API
const onPickVideo3 = () => {
var cmr = plus.camera.getCamera()
try {
cmr.startVideoCapture(
() => {
alert('ok')
},
() => {
alert('err')
},
{},
)
} catch (e) {
} finally {
cmr.stopVideoCapture()
}
}
//
const onPickVideo = () => { const onPickVideo = () => {
uni.chooseVideo({ uni.chooseVideo({
sourceType: ['album', 'camera'], // sourceType: ['album', 'camera'],
sourceType: ['album'],
maxDuration: 60,
compressed: true, compressed: true,
camera: 'back',
albumMode: 'custom',
// extension: uploadConfig.video.supportType,
success: (res: any) => {
console.log(res)
const tempFile = res.tempFile
tempFile.path = res.tempFilePath
//
addUploadQueue([tempFile], uploadFileTypeEm.video)
},
fail: (err) => {
uni.showToast({
title: '选取视频失败',
icon: 'none',
})
},
})
}
//
const onPickVideo2 = () => {
uni.chooseVideo({
sourceType: ['album', 'camera'],
maxDuration: 60,
compressed: true,
camera: 'back',
// extension: uploadConfig.video.supportType, // extension: uploadConfig.video.supportType,
success: (res: any) => { success: (res: any) => {
console.log(res) console.log(res)
@ -1561,7 +1641,6 @@ const stopMsg = () => {
stopStreamMsg = true stopStreamMsg = true
} }
async function sendText() { async function sendText() {
console.log('uploadList: ', uploadList)
if (uploadList.length > 0) { if (uploadList.length > 0) {
const isUpLoading = uploadList.some((file) => { const isUpLoading = uploadList.some((file) => {
// return file.status==="error" || file.status==="pending" // return file.status==="error" || file.status==="pending"
@ -1578,18 +1657,16 @@ async function sendText() {
} }
} }
const msg = inputText.value.trim() const msg = inputText.value.trim()
if (!msg && !refreshSend.value) { if (!msg) {
return showToastErr('不可以发送空消息!') return showToastErr('不可以发送空消息!')
} }
// if (uploadList.length > 0) { // if (uploadList.length > 0) {
// return showToastErr('!') // return showToastErr('!')
// } // }
if (!sendTextLoading.value) { if (!sendTextLoading.value) {
sendTextLoading.value = true
return showToastErr('正在接收消息请稍后') return showToastErr('正在接收消息请稍后')
} }
//
sendTextLoading.value = false
// //
// + // +
@ -1741,16 +1818,16 @@ async function sendText() {
} }
} }
} else { } else {
if (!refreshSend.value) { // if (!refreshSend.value) {
// //
addMessage({ addMessage({
role: 'user', role: 'user',
type: 'text', type: 'text',
content: msg, content: msg,
timestamp: new Date(), timestamp: new Date(),
mask: 'new', mask: 'new',
}) })
} // }
// //
chatMode.value = 'tongyi-app' //'tongyi-app'; qwen-long chatMode.value = 'tongyi-app' //'tongyi-app'; qwen-long
@ -1782,7 +1859,6 @@ async function sendText() {
// + // +
// //
console.log('message: ', messages)
uploadList.splice(0, uploadList.length) // uploadList.splice(0, uploadList.length) //
const list = formatData(messages) const list = formatData(messages)
@ -1790,9 +1866,38 @@ async function sendText() {
body.detail = JSON.stringify(messages) body.detail = JSON.stringify(messages)
aiMsg.content = '' aiMsg.content = ''
addMessage(aiMsg) addMessage(aiMsg)
send(body)
// return // return
// return // return
// //
}
const spliceMsg = (list, model) => {
let file = false
let image = false
let video = false
const length = list.length
console.log(list)
for (let i = length - 1; i >= 0; i--) {
const item = list[i]
if (model === 'tongyi-long' && item.type === 'image' && item.type === 'video') {
const index = length - i - 1
return list.splice(i - 1)
} else if (model !== 'tongyi-long' && item.type === 'file') {
const index = i
return list.splice(index + 1)
}
}
return list
}
const send = async (body) => {
// refreshSend.value = true; //
//
sendTextLoading.value = false //
const [aiMsg] = messages.slice(-1)
const recordList = messages.slice(0, messages.length - 1)
body.detail = JSON.stringify(recordList)
// body.messages = spliceMsg(body.messages, chatMode.value)
try { try {
// aiMsg.content = '' // aiMsg.content = ''
// //
@ -1801,10 +1906,14 @@ async function sendText() {
const signal = controller.signal const signal = controller.signal
const resp = await fetch(baseUrl + '/chat/app/completion', { const resp = await fetch(baseUrl + '/chat/app/completion', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: token.value }, headers: {
'Content-Type': 'application/json',
Authorization: token.value,
},
body: JSON.stringify(body), body: JSON.stringify(body),
signal: signal, signal: signal,
}) })
console.log(resp)
const reader = resp.body!.getReader() const reader = resp.body!.getReader()
const decoder = new TextDecoder() const decoder = new TextDecoder()
@ -1839,13 +1948,17 @@ async function sendText() {
const json = JSON.parse(chunk) const json = JSON.parse(chunk)
const delta = json.choices?.[0]?.delta?.content const delta = json.choices?.[0]?.delta?.content
if (delta) { if (delta) {
msgLoading.value = false
aiMsg.content += delta aiMsg.content += delta
// msgLoading.value = false
//messages //messages
messages[messages.length - 1] = { ...aiMsg } messages[messages.length - 1] = { ...aiMsg }
scrollToBottom() scrollToBottom()
} }
} catch {} } catch (e) {
console.log(e)
} finally {
console.log('over')
}
} }
// //
@ -1871,6 +1984,13 @@ async function sendText() {
console.log('chunk------------------: ') console.log('chunk------------------: ')
} }
} }
if (isJsonObject(buffer)) {
const response = JSON.parse(buffer)
if (response.code === 401) {
showToastErr('请重新登录')
}
}
scrollToBottom() scrollToBottom()
} catch (err) { } catch (err) {
// aiMsg.content = '' // aiMsg.content = ''
@ -1880,7 +2000,7 @@ async function sendText() {
} finally { } finally {
sendTextLoading.value = true sendTextLoading.value = true
showActions.value = false showActions.value = false
refreshSend.value = false // // refreshSend.value = false //
msgLoading.value = false msgLoading.value = false
} }
} }
@ -1899,7 +2019,16 @@ function copyText(msg: IMessage) {
} }
} }
function refreshText() { const msgType = (msg) => {
return (
msg &&
msg.role === 'user' &&
(msg.type === 'text' || msg.type === 'image' || msg.type === 'video')
)
}
function refreshText(msg) {
console.log('refresh msg', msg)
if (!sendTextLoading.value) { if (!sendTextLoading.value) {
// //
return return
@ -1910,98 +2039,57 @@ function refreshText() {
// 1. // 1.
const userMessages = messages.filter((msg) => msg.role === 'user') const userMessages = messages.filter((msg) => msg.role === 'user')
// const lastTwoUserMsgs = userMessages.slice(-2) // const lastTwoUserMsgs = userMessages.slice(-2)
const [msg1, msg2] = deepClone(userMessages.slice(-2)) // const [msg1, msg2, msg3] = deepClone(userMessages.slice(-3))
// let text=lastTwoUserMsgs[0] // lastTwoUserMsgs.every((msg)=>msg.type==="text" || msg.type==="image" || msg.type==="video" || msg.type==="file") const newMsgArr = deepClone(userMessages.slice(-3))
// let file=lastTwoUserMsgs[1] // lastTwoUserMsgs.every((msg)=>msg.type==="text" || msg.type==="image" || msg.type==="video" || msg.type==="file")
// 2. // 2.
let refreshText = null let text = null
const refreshFiles: UploadFile[] = [] const refreshFiles: UploadFile[] = []
if (msg1 && msg1.type === 'text' && msg2 && msg2.type !== 'text') { for (let i = newMsgArr.length - 1; i >= 0; i--) {
msg1.mask = 'new' const msg = newMsgArr[i]
msg2.mask = 'new' if (msg.type === 'text') {
refreshFiles.push(msg1) refreshFiles.unshift(msg)
refreshFiles.push(msg2) break
} else if (msg1.type === 'text' && msg1.role === 'user' && !msg2) { } else {
msg1.mask = 'new' refreshFiles.unshift(msg)
refreshFiles.push(msg1) }
} else if (msg2.type === 'text' && msg2.role === 'user' && !msg1) {
msg2.mask = 'new'
refreshFiles.push(msg2)
} else {
msg2.mask = 'new'
refreshFiles.push(msg2)
} }
// lastTwoUserMsgs.forEach((msg,i) => {
// console.log('msg: ',msg);
// if (msg.type === 'text' && msg.role==="user") {
// refreshText = msg.content //
// refreshFiles.push({
// content:msg.content,
// type:"text",
// role:"user",
// timestamp:new Date(),
// mask:"new"
// })
// } else if(msg.type==="video"){
// msg.mask="new"
// refreshFiles.push(msg)
// // msg.content.forEach((file : any) => {
// // console.log('lastTwoUserMsgs file: ',file);
// // refreshFiles.push({
// // id: guid.getGuid(),
// // url: file.video_url.url,
// // status: 'success',
// // name: file.name || '',
// // size: file.size || 0,
// // uploadFileType: file.uploadFileType || detectFileType(file.video_url.url),
// // })
// // })
// }else if(msg.type==="image"){
// msg.mask="new"
// refreshFiles.push(msg)
// // msg.content.forEach((file : any) => {
// // console.log('lastTwoUserMsgs file: ',file);
// // refreshFiles.push({
// // id: guid.getGuid(),
// // url: file.image_url.url,
// // status: 'success',
// // name: file.name || '',
// // size: file.size || 0,
// // uploadFileType: file.uploadFileType || detectFileType(file.image_url.url),
// // })
// // })
// }else{
// msg.mask="new"
// refreshFiles.push(msg)
// // msg.content.forEach((file : any) => {
// // console.log('lastTwoUserMsgs file: ',file);
// // refreshFiles.push({
// // id: guid.getGuid(),
// // url: file.content,
// // status: 'success',
// // name: file.name || '',
// // size: file.size || 0,
// // uploadFileType: file.uploadFileType || detectFileType(file.content),
// // })
// // })
// }
// })
// 3. // 3.
// inputText.value = refreshText // inputText.value = text
// uploadList.splice(0, uploadList.length, ...refreshFiles) // uploadList.splice(0, uploadList.length, ...refreshFiles)
refreshFiles.forEach((ele) => { refreshFiles.forEach((ele) => {
messages.push(ele) messages.push(ele)
}) })
refreshSend.value = true
// inputText.value = refreshText // return
// refreshSend.value = true
// inputText.value = text
// 4. // 4.
setTimeout(() => { // setTimeout(() => {
sendText() // sendText()
}, 100) // }, 100)
let list = formatData(messages)
const aiMsg = {
role: 'assistant',
type: 'text',
content: '',
timestamp: new Date(),
}
messages.push(aiMsg)
const body = {
model: chatMode.value, //
max_tokens: 1000,
top_p: 1,
presence_penalty: 0,
frequency_penalty: 0,
messages: list, // text ? [aiMsg] : historyUserMsgs,
stream: true,
listUuid: listUuid.value,
// listUuid:"eff18a10-1719-4528-ad63-ee5c01d0a412"
}
send(body)
} }
// URL // URL

View File

@ -202,4 +202,6 @@ async function sendText1(msgData = '') {
loading.value = false loading.value = false
showActions.value = false showActions.value = false
} }
} }
export const TOKEN="79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941ca1430937103230a1e32a1715f569f3efdbe6f8cb8b7b8642bd679668081b9b08f693d1b5be6002d936ec51e1e3e0c4927de9e32ac99a109b326e5d2bda27ec87624bb416ec70d2a95a2e190feeba9f0d6bae8571b3dfe89c824712344759a8f2bff9d70747c52525cf6a5614f9c770bca461a9b9c247b6dca97bcf83bbaf99bb726752c4fe1e9a4aa7de5c4cf3e88a3e480801280d45cdc124f9d8221105d852945dc6ce10bc1647e4f09dff4d52ffdfcd57b2349fd3262098015f94b8786aabc0d8a8098a126bf2449839db7ded893783707a3f776e4ff20f9e79ce24ba97e5f82085d12a8e518fe6dedcd453a773bb4cb26657088a4b3cd06b62cd9f9738196"

View File

@ -5,6 +5,10 @@ export const fileSuffix = (str) => {
let reg = /\.\w*$/ let reg = /\.\w*$/
return str.match(reg)[0] return str.match(reg)[0]
} }
export const isJsonObject = (json) => {
const str = json.trim()
return str.startsWith('{') && str.endsWith('}')
}
export const officeFileTypeList = ['.docx', '.doc', '.xls', '.xlsx', '.pdf', '.txt'] export const officeFileTypeList = ['.docx', '.doc', '.xls', '.xlsx', '.pdf', '.txt']
export const videoFileType = ['.mp4', '.mov', '.wmv'] export const videoFileType = ['.mp4', '.mov', '.wmv']
export const picFileType = ['.jpg', '.png', '.jpeg'] export const picFileType = ['.jpg', '.png', '.jpeg']
@ -112,7 +116,7 @@ export function formatData(list) {
result.push({ result.push({
role: 'user', role: 'user',
content: content, content: content,
type: 'image', type: item.type,
mask: item.mask, mask: item.mask,
}) })
} else if (item.type === 'file') { } else if (item.type === 'file') {
@ -171,15 +175,3 @@ export async function readFile(file, chunkSize = 10 * 1024 * 1024) {
const buffer = await blob.blob() const buffer = await blob.blob()
return sliceFile(buffer, chunkSize) return sliceFile(buffer, chunkSize)
} }
function uploadChunkFile({ chunk, fileName }, index, total, fileId) {
const formData = new FormData()
formData.append('Chunk', chunk)
formData.append('ChunkFileName', `${fileName}_${index}`)
formData.append('total', total)
formData.append('UseType', 100)
formData.append('FileName', fileName)
formData.append('Source', 'aiChat')
formData.append('UseType', 100)
return
}