Compare commits
2 Commits
35bc2f99e6
...
065d1b556f
Author | SHA1 | Date | |
---|---|---|---|
|
065d1b556f | ||
|
8a636bfde3 |
BIN
AIchat.rar
BIN
AIchat.rar
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/feige996/unibest">
|
<a href="https://github.com/feige996/unibest">
|
||||||
<img width="160" src="./src/static/logo.svg">
|
<img width="160" src="./src/static/logo.png">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
</route>
|
</route>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-screen bg-gray-50">
|
<div class="flex flex-col h-screen bg-#ffffff">
|
||||||
<!-- Navigation Bar -->
|
<!-- Navigation Bar -->
|
||||||
<div
|
<div
|
||||||
class="flex-none flex items-center justify-between px-5 py-3 bg-white shadow-md h-10 pt-10 z-999"
|
class="flex-none flex items-center justify-between px-5 py-3 bg-white shadow-md h-20 pt-10 z-999 fixed top-0 w-full box-border"
|
||||||
>
|
>
|
||||||
<image src="/static/aichat/black.png" class="w-2 h-4" @click="goBack" />
|
<image src="/static/aichat/black.png" class="w-3 h-4" @click="goBack" />
|
||||||
<div class="text-lg font-medium ml-12">小墨</div>
|
<div class="text-lg font-medium ml-12">小墨</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<!-- v-if="rawList.length > 0" -->
|
<!-- v-if="rawList.length > 0" -->
|
||||||
@ -21,17 +21,18 @@
|
|||||||
<image src="/static/aichat/new.png" class="w-5 h-5" @click="newChat" />
|
<image src="/static/aichat/new.png" class="w-5 h-5" @click="newChat" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 消息区 -->
|
<!-- 消息区 -->
|
||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
'flex relative p-b-10',
|
'flex fixed top-0 w-full p-b-10 box-border mt-20',
|
||||||
showActions ? (uploadList.length ? 'h-118' : 'h-137') : 'h-157',
|
showActions ? (uploadList.length ? 'h-118' : 'h-151') : 'h-171',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<!-- 背景层 -->
|
<!-- 背景层 -->
|
||||||
<div
|
<div
|
||||||
v-if="!messages.length"
|
v-if="!messages.length"
|
||||||
class="absolute inset-0 flex flex-col items-center justify-center pointer-events-none"
|
class="absolute inset-0 flex flex-col items-center justify-center pointer-events-none bg-#ffffff"
|
||||||
>
|
>
|
||||||
<image src="/static/aichat/logo.png" class="w-20 h-24 mb-4" @click="newChat" />
|
<image src="/static/aichat/logo.png" class="w-20 h-24 mb-4" @click="newChat" />
|
||||||
<view class="text-xl font-medium mb-1">嗨! 我是小墨</view>
|
<view class="text-xl font-medium mb-1">嗨! 我是小墨</view>
|
||||||
@ -40,40 +41,53 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
ref="scrollEl"
|
ref="scrollEl"
|
||||||
class="flex-1 overflow-y-auto bg-gray-50"
|
class="flex-1 overflow-y-auto bg-#ffffff"
|
||||||
:class="showActions ? 'pb-44' : 'pb-16'"
|
:class="showActions ? 'pb-44' : 'pb-16'"
|
||||||
>
|
>
|
||||||
<div :class="['relative z-10 px-4 py-6', showActions ? 'mb--11 h-105' : 'mb--21 h-135']">
|
<div :class="['relative z-10 px-4 py-6', showActions ? 'mb--11 h-105' : 'mb--21 h-135']">
|
||||||
<template v-for="(msg, idx) in messages" :key="idx">
|
<template v-for="(msg, idx) in messages" :key="idx">
|
||||||
<view v-if="shouldShowTimestamp(idx)" class="text-center text-xs text-gray-500 my-2">
|
<view v-if="shouldShowTimestamp(idx)" class="text-center text-xs text-gray-500 mt--3">
|
||||||
{{ formatDayGroup(msg.timestamp) }}
|
{{ formatDayGroup(msg.timestamp) }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="flex items-start"
|
class="flex items-start"
|
||||||
:class="msg.role === 'assistant' ? 'justify-start' : 'justify-end'"
|
:class="msg.role === 'assistant' ? 'justify-start mt-0.3' : 'justify-end mt-2 '"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
v-if="msg.role === 'assistant'"
|
v-if="msg.role === 'assistant'"
|
||||||
src="/static/aichat/logo-message.png"
|
src="/static/aichat/logo-message.png"
|
||||||
class="w-8 h-8 rounded-full mr-2 mt-1"
|
class="w-8 h-8 rounded-full mr-2 mt-1"
|
||||||
/>
|
/>
|
||||||
<view class="relative max-w-[54%] mt-4 mb-3">
|
<view
|
||||||
|
class="relative max-w-[76.5%] mt-5"
|
||||||
|
:class="idx === messages.length - 1 ? 'mb-20' : 'mb-3'"
|
||||||
|
>
|
||||||
<view
|
<view
|
||||||
:class="[
|
:class="[
|
||||||
'absolute -top-4 text-xs text-gray-400 w-20 text-right',
|
'absolute -top-5 text-xs text-gray-400 w-20 text-right ',
|
||||||
msg.role === 'assistant' ? 'left-0' : 'right-0',
|
msg.role === 'assistant' ? 'left--4' : 'right-0',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{ formatTimeShort(msg.timestamp) }}
|
{{ formatTimeShort(msg.timestamp) }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
:class="[
|
:class="[
|
||||||
'py-2 pl-2 rounded-md break-words mt-1',
|
'py-3 pl-3 rounded-md break-words mb-3 tracking-[2rpx] min-w-10 min-h-2 ',
|
||||||
msg.role === 'assistant'
|
msg.role === 'assistant'
|
||||||
? 'bg-[#f9f8fd] text-black shadow pb-1'
|
? 'bg-[#f9f8fd] text-black shadow '
|
||||||
: 'bg-[#45299e] text-white ',
|
: 'bg-[#45299e] text-white ',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
|
<wd-loading
|
||||||
|
v-show="msg.role === 'assistant' && msgLoading && idx === messages.length - 1"
|
||||||
|
:size="20"
|
||||||
|
color="#e3e3e3"
|
||||||
|
custom-class="loading-black"
|
||||||
|
:class="[
|
||||||
|
'absolute top-1.5 text-xs text-gray-400 w-20 text-right',
|
||||||
|
msg.role === 'assistant' ? 'left-1' : 'right-0',
|
||||||
|
]"
|
||||||
|
/>
|
||||||
<!-- 图片消息 -->
|
<!-- 图片消息 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
scroll-x
|
scroll-x
|
||||||
@ -84,21 +98,31 @@
|
|||||||
<view
|
<view
|
||||||
v-for="(file, fileIdx) in msg.content"
|
v-for="(file, fileIdx) in msg.content"
|
||||||
:key="fileIdx"
|
:key="fileIdx"
|
||||||
style="flex: 0 0 2.5rem"
|
class="relative rounded-md overflow-hidden mr-1"
|
||||||
class="relative h-10 rounded-md overflow-hidden mr-1"
|
:class="{
|
||||||
|
'w-60 h-60': msg.content.length == 1,
|
||||||
|
'w-15 h-15': msg.content.length == 2,
|
||||||
|
'w-30 h-15 ': msg.content.length == 3,
|
||||||
|
' h-15 flex-grow-0 flex-shrink-0 basis-10': msg.content.length >= 4,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<view
|
<view
|
||||||
|
v-if="showImageMask && fileIdx === 4"
|
||||||
class="absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center"
|
class="absolute top-0 left-0 right-0 bottom-0 flex items-center justify-center"
|
||||||
:class="{ 'bg-black bg-opacity-70': showImageMask && fileIdx === 3 }"
|
:class="{ 'bg-black bg-opacity-70': showImageMask && fileIdx === 4 }"
|
||||||
v-if="showImageMask && fileIdx === 3"
|
|
||||||
>
|
>
|
||||||
+{{ msg.content.length - 3 }}
|
+{{ msg.content.length - 4 }}
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<img
|
<image
|
||||||
v-if="file.uploadFileType === uploadFileTypeEm.image"
|
v-if="file.uploadFileType === uploadFileTypeEm.image"
|
||||||
:src="file.url || file.tempFilePath"
|
:src="file.url || file.tempFilePath"
|
||||||
class="w-full h-full object-cover"
|
:class="{
|
||||||
|
'w-100% h-100%': msg.content.length == 1,
|
||||||
|
'w-15 h-15': msg.content.length == 2,
|
||||||
|
'w-40 h-15 ': msg.content.length == 3,
|
||||||
|
'w-40 h-15 object-cover': msg.content.length >= 4,
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -148,14 +172,10 @@
|
|||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
v-if="msg.role === 'assistant' && msg.type === 'text'"
|
v-if="msg.role === 'assistant' && msg.type === 'text'"
|
||||||
class="absolute bottom-0 flex space-x-3 ml-1 mb--5.5"
|
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
|
<image src="/static/aichat/resect.png" class="w-4.3 h-4" @click="refreshText()" />
|
||||||
src="/static/aichat/resect.png"
|
|
||||||
class="w-4 h-4"
|
|
||||||
@click="refreshText(msg)"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<image
|
<image
|
||||||
@ -173,7 +193,7 @@
|
|||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
'fixed bottom-0 left-0 right-0 bg-white z-[80] overflow-hidden transition-all duration-300',
|
'fixed bottom-0 left-0 right-0 bg-white z-[80] overflow-hidden transition-all duration-300',
|
||||||
showActions ? (uploadList.length ? 'h-58' : 'h-40') : 'h-20',
|
showActions ? (uploadList.length ? 'h-60' : 'h-40') : 'h-20',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<!-- 上传列表 -->
|
<!-- 上传列表 -->
|
||||||
@ -230,16 +250,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 知识库-->
|
||||||
|
|
||||||
|
<div
|
||||||
|
@click="toggleKnowledge"
|
||||||
|
v-if="!uploadList.length"
|
||||||
|
class="fixed left-[32rpx] right-0 z-[90] h-8 w-23 flex items-center justify-between px-3 box-border rounded-1 transition-all duration-300"
|
||||||
|
:class="[
|
||||||
|
knowledgeOpen ? 'bg-#eee9f8' : 'bg-[#F9F9F9]',
|
||||||
|
showActions ? (uploadList.length ? 'bottom-31' : 'bottom-41') : 'bottom-21',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
:src="
|
||||||
|
knowledgeOpen
|
||||||
|
? '/static/aichat/Knowledge-open.png'
|
||||||
|
: '/static/aichat/Knowledge-close.png'
|
||||||
|
"
|
||||||
|
class="w-4 h-3.5 mt-1"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
:class="['text-[26rpx] transition-colors', knowledgeOpen ? 'text-#46299D' : 'text-black']"
|
||||||
|
>
|
||||||
|
知识库
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 输入 + 切换 -->
|
<!-- 输入 + 切换 -->
|
||||||
<view class="flex items-center px-4 py-2.5 border-t border-t-solid border-[#E7E7E7]">
|
<view class="flex items-center px-4 py-2.5 border-t border-t-solid border-[#E7E7E7]">
|
||||||
<input
|
<input
|
||||||
v-model="inputText"
|
v-model="inputText"
|
||||||
@keyup.enter="sendText"
|
@keyup.enter="sendText('')"
|
||||||
placeholder="想对我说点什么~"
|
placeholder="想对我说点什么~"
|
||||||
class="flex-1 h-10 px-3 border border-gray-100 bg-[#f9f9f9] rounded-full focus:outline-none"
|
class="flex-1 h-10 px-3 border border-gray-100 bg-[#f9f9f9] rounded-1 focus:outline-none"
|
||||||
/>
|
/>
|
||||||
<image
|
<image
|
||||||
|
v-show="!knowledgeOpen"
|
||||||
src="/static/aichat/add-circle.png"
|
src="/static/aichat/add-circle.png"
|
||||||
class="w-7 h-7 mx-3"
|
class="w-7 h-7 mx-3"
|
||||||
@click="toggleActions"
|
@click="toggleActions"
|
||||||
@ -251,8 +297,9 @@
|
|||||||
<image
|
<image
|
||||||
src="/static/aichat/enter.png"
|
src="/static/aichat/enter.png"
|
||||||
class="w-7 h-7"
|
class="w-7 h-7"
|
||||||
@click="sendText"
|
@click="sendText('')"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
|
:class="[knowledgeOpen ? 'ml-2' : 'ml-0']"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -260,7 +307,10 @@
|
|||||||
<transition name="slide-up">
|
<transition name="slide-up">
|
||||||
<view
|
<view
|
||||||
v-show="showActions"
|
v-show="showActions"
|
||||||
class="flex justify-around items-center h-20 bg-white border-t border-t-solid border-[#E7E7E7]"
|
:class="[
|
||||||
|
'flex justify-around items-center h-20 bg-white border-t border-t-solid border-[#E7E7E7]',
|
||||||
|
showActions ? (uploadList.length ? 'pt-1' : 'pt-1') : 'pt-0',
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<view class="flex flex-col items-center">
|
<view class="flex flex-col items-center">
|
||||||
<image src="/static/aichat/phone-img.png" class="w-13 h-13" @click="onPickImage" />
|
<image src="/static/aichat/phone-img.png" class="w-13 h-13" @click="onPickImage" />
|
||||||
@ -429,13 +479,12 @@ async function goChat(listUuid: string) {
|
|||||||
const listUuid = ref('')
|
const listUuid = ref('')
|
||||||
|
|
||||||
async function createChatSession() {
|
async function createChatSession() {
|
||||||
console.log(token.value, 'wwww')
|
|
||||||
try {
|
try {
|
||||||
const createResp: any = await uni.request({
|
const createResp: any = await uni.request({
|
||||||
url: `${baseUrl}/chat/create`,
|
url: `${baseUrl}/chat/create`,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
gptModel: 'gpt-3.5-turbo',
|
gptModel: 'gpt-4-vision-preview',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
Authorization: token.value,
|
Authorization: token.value,
|
||||||
@ -483,7 +532,7 @@ async function fetchHistoryDiets(value) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
listUuid: value,
|
listUuid: value,
|
||||||
gptModel: 'gpt-3.5-turbo',
|
gptModel: 'gpt-4-vision-preview',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
Authorization: token.value,
|
Authorization: token.value,
|
||||||
@ -497,18 +546,21 @@ async function fetchHistoryDiets(value) {
|
|||||||
console.error('fetchHistoryList error:', err)
|
console.error('fetchHistoryList error:', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const token = ref<string>('')
|
const token = ref<string>(
|
||||||
|
'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941ca1430937103230a1e32a1715f569f3efdbe6f8cb8b7b8642bd679668081b9b08f693d1b5be6002d936ec51e1e3e0c4927de9e32ac99a109b326e5d2bda27ec87624bb416ec70d2a95a2e190feeba9f0d6bae8571b3dfe89c824712344759a8f2bff9d70747c52525cf6a5614f9c770bca461a9b9c247b6dca97bcf83bbaf99bb726752c4fe1e9a4aa7de5c4cf3e88a3e480801280d45cdc124f9d8221105d852945dc6ce10bc1647e4f09dff4d52ffdfc3ee452912e5908e2c574b766448c260449904f2a3c5ab9ed0235cfc8d5ba01f5d7c370733b136f7775849b03324fc6532d108779f9a7ff8dc40f235c56fec1b7a11ad61ac7e0a6a86f198079f4b92d61',
|
||||||
|
)
|
||||||
const userInfo = ref<any>({})
|
const userInfo = ref<any>({})
|
||||||
const refreshToken = ref<string>('')
|
const refreshToken = ref<string>('')
|
||||||
const statusBarHeight = ref<number>(0)
|
const statusBarHeight = ref<number>(0)
|
||||||
const mask = ref('')
|
const mask = ref('')
|
||||||
// ---- 页面初始化 ----
|
// ---- 页面初始化 ----
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 1. 定义一个 init 函数,拿 Extras 并依次调用接口
|
// 1. 定义一个 init 函数,拿 Extras 并依次调用接口
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
const wv = plus.webview.currentWebview()
|
const wv = plus.webview.currentWebview()
|
||||||
|
// token.value = wv.token || uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN
|
||||||
token.value = wv.token || uni.getStorageSync('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
|
||||||
@ -517,29 +569,31 @@ onMounted(() => {
|
|||||||
await createChatSession()
|
await createChatSession()
|
||||||
await fetchHistoryList()
|
await fetchHistoryList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 如果在 Plus 环境里,等 plusready
|
|
||||||
if (window.plus && plus.webview) {
|
|
||||||
document.addEventListener('plusready', init, false)
|
|
||||||
// plusready 可能已经触发过,直接再调用一次以防万一
|
|
||||||
if (plus.webview.currentWebview()) {
|
|
||||||
init()
|
init()
|
||||||
}
|
|
||||||
}
|
|
||||||
// 3. 普通 H5 调试,直接从 storage/SystemInfo 拿
|
|
||||||
else {
|
|
||||||
token.value = import.meta.env.VITE_DEV_TOKEN || uni.getStorageSync('token') || wv.token
|
|
||||||
userInfo.value = uni.getStorageSync('userInfo')
|
|
||||||
refreshToken.value = uni.getStorageSync('refreshToken')
|
|
||||||
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight
|
|
||||||
|
|
||||||
createChatSession().then(fetchHistoryList)
|
// // 2. 如果在 Plus 环境里,等 plusready
|
||||||
}
|
// if (window.plus && plus.webview) {
|
||||||
|
// document.addEventListener('plusready', init, false)
|
||||||
|
// // plusready 可能已经触发过,直接再调用一次以防万一
|
||||||
|
// if (plus.webview.currentWebview()) {
|
||||||
|
// init()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // 3. 普通 H5 调试,直接从 storage/SystemInfo 拿
|
||||||
|
// else {
|
||||||
|
// token.value = uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN
|
||||||
|
// userInfo.value = uni.getStorageSync('userInfo')
|
||||||
|
// refreshToken.value = uni.getStorageSync('refreshToken')
|
||||||
|
// statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight
|
||||||
|
// createChatSession().then(fetchHistoryList)
|
||||||
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
function scrollToBottom() {
|
function scrollToBottom() {
|
||||||
const el = scrollEl.value!
|
const el = scrollEl.value!
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
// el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })
|
||||||
|
console.log(el.scrollHeight, 'el.scrollHeight')
|
||||||
el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })
|
el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -551,6 +605,9 @@ const onScroll = (e) => {
|
|||||||
|
|
||||||
//查看更多图片
|
//查看更多图片
|
||||||
const previewMoreImg = (files) => {
|
const previewMoreImg = (files) => {
|
||||||
|
uni.removeStorageSync('previewImages')
|
||||||
|
uni.removeStorageSync('previewVideos')
|
||||||
|
|
||||||
uni.setStorageSync('previewImages', files)
|
uni.setStorageSync('previewImages', files)
|
||||||
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
@ -560,6 +617,9 @@ const previewMoreImg = (files) => {
|
|||||||
|
|
||||||
//查看视频
|
//查看视频
|
||||||
const previewVideo = (files) => {
|
const previewVideo = (files) => {
|
||||||
|
uni.removeStorageSync('previewVideos')
|
||||||
|
uni.removeStorageSync('previewImages')
|
||||||
|
|
||||||
uni.setStorageSync('previewVideos', files)
|
uni.setStorageSync('previewVideos', files)
|
||||||
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
@ -762,7 +822,6 @@ const uploadFile = (file: UploadFile) => {
|
|||||||
// 照片
|
// 照片
|
||||||
const onPickImage = () => {
|
const onPickImage = () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 10, // 最多选择9张
|
count: 10, // 最多选择9张
|
||||||
sizeType: ['original', 'compressed'],
|
sizeType: ['original', 'compressed'],
|
||||||
@ -811,7 +870,7 @@ const onPickVideo = () => {
|
|||||||
const onPickFile = () => {
|
const onPickFile = () => {
|
||||||
uni.chooseFile({
|
uni.chooseFile({
|
||||||
count: 10,
|
count: 10,
|
||||||
extension: uploadConfig.file.supportType,
|
type: uploadConfig.file.supportType,
|
||||||
success: (res: any) => {
|
success: (res: any) => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
// 开始上传
|
// 开始上传
|
||||||
@ -852,11 +911,17 @@ const previewFile = (url: string) => {
|
|||||||
url: '/pages/webview/index?link=' + encodeURIComponent(url),
|
url: '/pages/webview/index?link=' + encodeURIComponent(url),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const msgLoading = ref(true)
|
||||||
// 发送消息
|
// 发送消息
|
||||||
async function sendText(msg) {
|
async function sendText(msgData) {
|
||||||
|
msgLoading.value = true
|
||||||
const text = inputText.value.trim()
|
const text = inputText.value.trim()
|
||||||
if (!text || loading.value) return
|
if (!text) {
|
||||||
|
uni.showToast({ title: '请输入信息', icon: 'error' })
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (loading.value) return
|
||||||
|
|
||||||
//获取本次发送的消息和文件
|
//获取本次发送的消息和文件
|
||||||
const tempUploadList = Object.assign([], uploadList)
|
const tempUploadList = Object.assign([], uploadList)
|
||||||
@ -923,9 +988,10 @@ async function sendText(msg) {
|
|||||||
content: text,
|
content: text,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
}
|
}
|
||||||
|
addMessage(aiMsg)
|
||||||
//清除上传列表
|
//清除上传列表
|
||||||
uploadList.splice(0, uploadList.length)
|
uploadList.splice(0, uploadList.length)
|
||||||
|
// resds.value = historyUserMsgs
|
||||||
|
|
||||||
const body: IGptRequestBody = {
|
const body: IGptRequestBody = {
|
||||||
model: 'gpt-4-vision-preview',
|
model: 'gpt-4-vision-preview',
|
||||||
@ -935,7 +1001,7 @@ async function sendText(msg) {
|
|||||||
top_p: 1,
|
top_p: 1,
|
||||||
presence_penalty: 0,
|
presence_penalty: 0,
|
||||||
frequency_penalty: 0,
|
frequency_penalty: 0,
|
||||||
messages: historyUserMsgs,
|
messages: msgData || historyUserMsgs,
|
||||||
stream: true,
|
stream: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,7 +1038,10 @@ async function sendText(msg) {
|
|||||||
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
|
||||||
|
//每次更新messages消息,实现流式输出
|
||||||
|
messages[messages.length - 1] = { ...aiMsg }
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
console.log('2')
|
console.log('2')
|
||||||
}
|
}
|
||||||
@ -981,8 +1050,6 @@ async function sendText(msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加AI消息
|
|
||||||
addMessage(aiMsg)
|
|
||||||
//更新上下文消息
|
//更新上下文消息
|
||||||
historyUserMsgs.push(aiMsg)
|
historyUserMsgs.push(aiMsg)
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
@ -1009,10 +1076,19 @@ function copyText(msg: IMessage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshText(msg: IMessage) {
|
function refreshText() {
|
||||||
const lastUserMsg = historyUserMsgs[historyUserMsgs.length - 1]
|
const lastUserMsg = historyUserMsgs[historyUserMsgs.length - 2]
|
||||||
|
// resds.value = lastUserMsg
|
||||||
|
|
||||||
sendText(lastUserMsg)
|
sendText(lastUserMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const knowledgeOpen = ref(false)
|
||||||
|
function toggleKnowledge() {
|
||||||
|
knowledgeOpen.value = !knowledgeOpen.value
|
||||||
|
showActions.value = false
|
||||||
|
rotation.value = 0
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -1,24 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="image-gallery grid grid-cols-4 gap-1 p-4" v-if="imageList.length > 0">
|
<view class="flex flex-col h-screen bg-#ffffff">
|
||||||
|
<view
|
||||||
|
class="flex-none flex items-center justify-between px-5 py-3 bg-white shadow-md h-20 pt-10 z-999 fixed top-0 w-full box-border"
|
||||||
|
>
|
||||||
|
<image src="/static/aichat/black.png" class="w-3 h-4 mt-1" @click="goBack" />
|
||||||
|
</view>
|
||||||
|
<view class="image-gallery grid grid-cols-4 gap-1 p-4 mt-20" v-if="imageList.length > 0">
|
||||||
<view
|
<view
|
||||||
v-for="(image, index) in imageList"
|
v-for="(image, index) in imageList"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="aspect-square overflow-hidden group"
|
class="aspect-square overflow-hidden group"
|
||||||
>
|
>
|
||||||
<image
|
<!-- <image
|
||||||
:src="image.url"
|
:src="image.url"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
class="w-full h-full"
|
class="w-full h-full"
|
||||||
@click="handleImageClick(index)"
|
@click="handleImageClick(index)"
|
||||||
/>
|
/> -->
|
||||||
|
|
||||||
|
<wd-img :width="100" :height="100" :src="image.url" :enable-preview="true" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="videoList.length > 0" class="flex items-center justify-center">
|
<view v-if="videoList.length > 0" class="flex items-center justify-center mt-30">
|
||||||
<view v-for="(video, index) in videoList" :key="index" class="w-full h-50">
|
<view v-for="(video, index) in videoList" :key="index" class="w-full h-50">
|
||||||
<video :src="video" class="w-full h-full" controls :poster="video.url"></video>
|
<video :src="video" class="w-full h-full" controls :poster="video.url"></video>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -30,8 +39,12 @@ const imageList = ref([])
|
|||||||
const videoList = ref([])
|
const videoList = ref([])
|
||||||
|
|
||||||
// 图片点击处理
|
// 图片点击处理
|
||||||
const handleImageClick = (index) => {
|
// const handleImageClick = (index) => {
|
||||||
uni.previewImage({ urls: [imageList.value[index].url] })
|
// uni.previewImage({ urls: [imageList.value[index].url] })
|
||||||
|
// }
|
||||||
|
// 返回上一个页面
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack({ delta: 1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生命周期钩子
|
// 生命周期钩子
|
||||||
|
BIN
src/static/aichat/Knowledge-close.png
Normal file
BIN
src/static/aichat/Knowledge-close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 776 B |
BIN
src/static/aichat/Knowledge-open.png
Normal file
BIN
src/static/aichat/Knowledge-open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 827 B |
BIN
src/static/logo.png
Normal file
BIN
src/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Loading…
Reference in New Issue
Block a user