

<script setup lang='ts'>
import type { Ref } from 'vue'
import { computed, onMounted, onUnmounted, ref,watch,h } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { storeToRefs } from 'pinia'
import { NAutoComplete, NButton, NInput, useDialog, useMessage,NAvatar,NModal,NCard,NImage } from 'naive-ui'
import html2canvas from 'html2canvas'
import { Message } from './components'
import { useScroll } from './hooks/useScroll'
import { useChat } from './hooks/useChat'
import { useUsingContext } from './hooks/useUsingContext'
import { getGpts } from '@/api/chatmsg';
import {  SvgIcon } from '@/components/common'
import { useBasicLayout } from '@/hooks/useBasicLayout'
import { gptConfigStore, gptsUlistStore, homeStore, useChatStore, usePromptStore,useAppStore } from '@/store'
import { chatSetting, fetchChatAPIProcess, gptsType, mlog, myFetch, my2Fetch } from '@/api'
import { t } from '@/locales'
import drawListVue from '../mj/drawList.vue'
import aiGPT from '../mj/aiGpt.vue'
import AiSiderInput from '../mj/aiSiderInput.vue'
import aiGptInput from '../mj/aiGptInput.vue'
import { getNotice,readNotice, getInform } from '@/api/notice'
import to from "await-to-js";

let controller = new AbortController()

const openLongReply = import.meta.env.VITE_GLOB_OPEN_LONG_REPLY === 'true'

const route = useRoute()
const dialog = useDialog()
const ms = useMessage()
const router = useRouter()
const chatStore = useChatStore()
// const href = window.location.href.split('#')[0]

const href = window.location.hostname;
const { isMobile } = useBasicLayout()
const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex } = useChat()
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll()
const { usingContext, toggleUsingContext } = useUsingContext()

const { uuid } = route.params as { uuid: string }

const dataSources = computed(() => chatStore.getChatByUuid(+uuid))
const conversationList = computed(() => dataSources.value.filter(item => (!item.inversion && !!item.conversationOptions)))

const prompt = ref<string>('')
const loading = ref<boolean>(false)
const inputRef = ref<Ref | null>(null)

// 添加PromptStore
const promptStore = usePromptStore()

// 使用storeToRefs，保证store修改后，联想部分能够重新渲染
const { promptList: promptTemplate } = storeToRefs<any>(promptStore)

const appStore = useAppStore()
const isChat = computed(() => appStore.isChat)

// 未知原因刷新页面，loading 状态不会重置，手动重置
dataSources.value.forEach((item, index) => {
	if (item.loading)
		updateChatSome(+uuid, index, { loading: false })
})

function handleSubmit() {
	//onConversation() //把这个放到aiGpt
	let message = prompt.value;
	if (!message || message.trim() === '')
		return
	if (loading.value) return;
	loading.value = true
	homeStore.setMyData({act:'gpt.submit', actData:{ prompt:prompt.value, uuid } });
	prompt.value='';
}

async function onConversation() {
	let message = prompt.value

	if (loading.value)
		return

	if (!message || message.trim() === '')
		return

	controller = new AbortController()

	addChat(
		+uuid,
		{
			dateTime: new Date().toLocaleString(),
			text: message,
			inversion: true,
			error: false,
			conversationOptions: null,
			requestOptions: { prompt: message, options: null },
		},
	)
	scrollToBottom()

	loading.value = true
	prompt.value = ''

	let options: Chat.ConversationRequest = {}
	const lastContext = conversationList.value[conversationList.value.length - 1]?.conversationOptions

	if (lastContext && usingContext.value)
		options = { ...lastContext }

	addChat(
		+uuid,
		{
			dateTime: new Date().toLocaleString(),
			text: '思考中',
			loading: true,
			inversion: false,
			error: false,
			conversationOptions: null,
			requestOptions: { prompt: message, options: { ...options } },
		},
	)
	scrollToBottom()

	try {
		let lastText = ''
		const fetchChatAPIOnce = async () => {
			await fetchChatAPIProcess<Chat.ConversationResponse>({
				prompt: message,
				options,
				signal: controller.signal,
				onDownloadProgress: ({ event }) => {
					const xhr = event.target
					const { responseText } = xhr
					// Always process the final line
					const lastIndex = responseText.lastIndexOf('\n', responseText.length - 2)
					let chunk = responseText
					if (lastIndex !== -1)
						chunk = responseText.substring(lastIndex)
					try {
						const data = JSON.parse(chunk)
						updateChat(
							+uuid,
							dataSources.value.length - 1,
							{
								dateTime: new Date().toLocaleString(),
								text: lastText + (data.text ?? ''),
								inversion: false,
								error: false,
								loading: true,
								conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
								requestOptions: { prompt: message, options: { ...options } },
							},
						)

						if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
							options.parentMessageId = data.id
							lastText = data.text
							message = ''
							return fetchChatAPIOnce()
						}

						scrollToBottomIfAtBottom()
					}
					catch (error) {
						//
					}
				},
			})
			updateChatSome(+uuid, dataSources.value.length - 1, { loading: false })
		}

		await fetchChatAPIOnce()
	}
	catch (error: any) {
		const errorMessage = error?.message ?? t('common.wrong')

		if (error.message === 'canceled') {
			updateChatSome(
				+uuid,
				dataSources.value.length - 1,
				{
					loading: false,
				},
			)
			scrollToBottomIfAtBottom()
			return
		}

		const currentChat = getChatByUuidAndIndex(+uuid, dataSources.value.length - 1)

		if (currentChat?.text && currentChat.text !== '') {
			updateChatSome(
				+uuid,
				dataSources.value.length - 1,
				{
					text: `${currentChat.text}\n[${errorMessage}]`,
					error: false,
					loading: false,
				},
			)
			return
		}

		updateChat(
			+uuid,
			dataSources.value.length - 1,
			{
				dateTime: new Date().toLocaleString(),
				text: errorMessage,
				inversion: false,
				error: true,
				loading: false,
				conversationOptions: null,
				requestOptions: { prompt: message, options: { ...options } },
			},
		)
		scrollToBottomIfAtBottom()
	}
	finally {
		loading.value = false
	}
}

async function onRegenerate(index: number) {
	if (loading.value)
		return

	controller = new AbortController()

	const { requestOptions } = dataSources.value[index]

	let message = requestOptions?.prompt ?? ''

	let options: Chat.ConversationRequest = {}

	if (requestOptions.options)
		options = { ...requestOptions.options }

	loading.value = true

	updateChat(
		+uuid,
		index,
		{
			dateTime: new Date().toLocaleString(),
			text: '',
			inversion: false,
			error: false,
			loading: true,
			conversationOptions: null,
			requestOptions: { prompt: message, options: { ...options } },
		},
	)

	try {
		let lastText = ''
		const fetchChatAPIOnce = async () => {
			await fetchChatAPIProcess<Chat.ConversationResponse>({
				prompt: message,
				options,
				signal: controller.signal,
				onDownloadProgress: ({ event }) => {
					const xhr = event.target
					const { responseText } = xhr
					// Always process the final line
					const lastIndex = responseText.lastIndexOf('\n', responseText.length - 2)
					let chunk = responseText
					if (lastIndex !== -1)
						chunk = responseText.substring(lastIndex)
					try {
						const data = JSON.parse(chunk)
						updateChat(
							+uuid,
							index,
							{
								dateTime: new Date().toLocaleString(),
								text: lastText + (data.text ?? ''),
								inversion: false,
								error: false,
								loading: true,
								conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
								requestOptions: { prompt: message, options: { ...options } },
							},
						)

						if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
							options.parentMessageId = data.id
							lastText = data.text
							message = ''
							return fetchChatAPIOnce()
						}
					}
					catch (error) {
						//
					}
				},
			})
			updateChatSome(+uuid, index, { loading: false })
		}
		await fetchChatAPIOnce()
	}
	catch (error: any) {
		if (error.message === 'canceled') {
			updateChatSome(
				+uuid,
				index,
				{
					loading: false,
				},
			)
			return
		}

		const errorMessage = error?.message ?? t('common.wrong')

		updateChat(
			+uuid,
			index,
			{
				dateTime: new Date().toLocaleString(),
				text: errorMessage,
				inversion: false,
				error: true,
				loading: false,
				conversationOptions: null,
				requestOptions: { prompt: message, options: { ...options } },
			},
		)
	}
	finally {
		loading.value = false
	}
}

function handleExport() {
	if (loading.value)
		return

	const d = dialog.warning({
		title: t('chat.exportImage'),
		content: t('chat.exportImageConfirm'),
		positiveText: t('common.yes'),
		negativeText: t('common.no'),
		onPositiveClick: async () => {
			try {
				d.loading = true
				const ele = document.getElementById('image-wrapper')
				const canvas = await html2canvas(ele as HTMLDivElement, {
					useCORS: true,
				})
				const imgUrl = canvas.toDataURL('image/png')
				const tempLink = document.createElement('a')
				tempLink.style.display = 'none'
				tempLink.href = imgUrl
				tempLink.setAttribute('download', 'chat-shot.png')
				if (typeof tempLink.download === 'undefined')
					tempLink.setAttribute('target', '_blank')

				document.body.appendChild(tempLink)
				tempLink.click()
				document.body.removeChild(tempLink)
				window.URL.revokeObjectURL(imgUrl)
				d.loading = false
				ms.success(t('chat.exportSuccess'))
				Promise.resolve()
			}
			catch (error: any) {
				ms.error(t('chat.exportFailed'))
			}
			finally {
				d.loading = false
			}
		},
	})
}

function handleDelete(index: number) {
	if (loading.value)
		return

	dialog.warning({
		title: t('chat.deleteMessage'),
		content: t('chat.deleteMessageConfirm'),
		positiveText: t('common.yes'),
		negativeText: t('common.no'),
		onPositiveClick: () => {
			chatStore.deleteChatByUuid(+uuid, index)
		},
	})
}

function handleClear() {
	if (loading.value)
		return

	dialog.warning({
		title: t('chat.clearChat'),
		content: t('chat.clearChatConfirm'),
		positiveText: t('common.yes'),
		negativeText: t('common.no'),
		onPositiveClick: () => {
			chatStore.clearChatByUuid(+uuid)
		},
	})
}

function handleEnter(event: KeyboardEvent) {
	if (!isMobile.value) {
		if (event.key === 'Enter' && !event.shiftKey) {
			event.preventDefault()
			handleSubmit()
		}
	}
	else {
		if (event.key === 'Enter' && event.ctrlKey) {
			event.preventDefault()
			handleSubmit()
		}
	}
}

function handleStop() {
	if (loading.value) {
		homeStore.setMyData({act:'abort'});
		controller.abort()
		loading.value = false
	}
}




// 可优化部分
// 搜索选项计算，这里使用value作为索引项，所以当出现重复value时渲染异常(多项同时出现选中效果)
// 理想状态下其实应该是key作为索引项,但官方的renderOption会出现问题，所以就需要value反renderLabel实现
const searchOptions = computed(() => {
	if (prompt.value.startsWith('/')) {
		const abc= promptTemplate.value.filter((item: { key: string }) => item.key.toLowerCase().includes(prompt.value.substring(1).toLowerCase())).map((obj: { value: any }) => {
			return {
				label: obj.value,
				value: obj.value,
			}
		})
		mlog('搜索选项', abc);
		return abc;
	}else if(prompt.value=='@'){
		const abc=  gptsUlistStore.myData.slice(0,10).map( (v:gptsType) => {
			return {
				label:v.info,
				gpts:v,
				value:v.gid
			}
		})
		return abc ;
	}else {
		return []
	}
})

const goUseGpts= async ( item: gptsType)=>{
	const saveObj= {model:  `${ item.modelName }`   ,gpts:item}
	gptConfigStore.setMyData(saveObj);
	if(chatStore.active){ //保存到对话框
		const chatSet = new chatSetting( chatStore.active );
		if( chatSet.findIndex()>-1 ) chatSet.save( saveObj )
	}
	ms.success(t('mjchat.success2'));
	// const gptUrl= `https://gpts.ddaiai.com/open/gptsapi/use`;
	// myFetch(gptUrl,item );

	mlog('go local ', homeStore.myData.local );
	if(homeStore.myData.local!=='Chat') router.replace({name:'Chat',params:{uuid:chatStore.active}});

	gptsUlistStore.setMyData( item );

}

// value反渲染key
const renderOption = (option: { label: string,gpts?:gptsType }) => {
	if( prompt.value=='@'){
		//return [ h( NAvatar,{src:'https://cos.aitutu.cc/gpts/gpt4all.jpg',size:"small",round:true}),option.label ]
		return [h("div",{class:'flex justify-start items-center'
				, onclick:()=>{
					if(option.gpts)   goUseGpts(option.gpts) ;
					prompt.value='';
					setTimeout(() =>  prompt.value='', 80);
				}}
			,[h(NAvatar,{src:option.gpts?.logo, "fallback-src" : 'https://cos.aitutu.cc/gpts/3.5net.png',size:"small",round:true, class:"w-8 h-8"})
				, h('span', { class: 'pl-1' }, option.gpts?.name  )
				, h('span', { class: 'line-clamp-1 flex-1 pl-1 opacity-50' }, option.label  )
			])]
	}
	for (const i of promptTemplate.value) {
		if (i.value === option.label)
			return [i.key]
	}
	return []
}

const placeholder = computed(() => {
	if (isMobile.value)
		return t('chat.placeholderMobile')
	return t('chat.placeholder')
})

const buttonDisabled = computed(() => {
	return loading.value || !prompt.value || prompt.value.trim() === ''
})

const footerClass = computed(() => {
	let classes = ['p-4']
	if (isMobile.value)
		classes = ['sticky', 'left-0', 'bottom-0', 'right-0', 'p-2', 'pr-3'] //, 'overflow-hidden'
	return classes
})


onMounted(() => {
	scrollToBottom()
	if (inputRef.value && !isMobile.value)
		inputRef.value?.focus()
	// 查询公告信息
	selectNotice()
	// 查询通知信息
	selectInform()
})

onUnmounted(() => {

	if (loading.value)   controller.abort()
	homeStore.setMyData({isLoader:false});
})

const local= computed(()=>homeStore.myData.local );
watch(()=>homeStore.myData.act,(n)=>{
	if(n=='draw')  scrollToBottom();
	if(n=='scrollToBottom') scrollToBottom();
	if(n=='scrollToBottomIfAtBottom') scrollToBottomIfAtBottom();
	if(n=='gpt.submit' || n=='gpt.resubmit'){ loading.value = true;}
	if(n=='stopLoading'){ loading.value = false;}
});
const st =ref({inputme:true});

watch( ()=>loading.value ,(n)=> homeStore.setMyData({isLoader:n }))

const ychat = computed( ()=>{
	let text= prompt.value
	if (loading.value) text= "";
	else {
		scrollToBottomIfAtBottom();
	}
	return { text, dateTime: t('chat.preview')} as Chat.Chat;
})

const showModal = ref(false);
const modalContent = ref('<h2>暂无内容</h2>');
const informContent = ref([]);
const noticeId = ref('');
async function selectNotice() {
	const [err, result] = await to(getNotice());
	console.log("result?.data",result?.data)
	if (result?.data) {
		showModal.value = true
		noticeId.value = result.data.noticeId
		modalContent.value = result.data.noticeContent
	}
}
async function selectInform() {
	const [err, result] = await to(getInform());
	if (result?.rows) {
		informContent.value = result.rows.length ? result.rows : []
	}
}

async function handleClose(){
	await to(readNotice(noticeId.value));
}
const gptsList = ref<gptsType[]>([]);
const gptsFilterList = ref<gptsType[]>([]);
const getRandowNum = (Min:number, Max: number):number =>{
	const Range = Max - Min + 1
	const Rand = Math.random()
	return Min + Math.floor(Rand * Range)
}
const load= async ()=>{

	// const gptUrl= homeStore.myData.session.gptUrl?  homeStore.myData.session.gptUrl :'';
	// mlog('load',gptUrl );
	//  let d;
	// if( homeStore.myData.session.gptUrl ){
	//    d = await my2Fetch( homeStore.myData.session.gptUrl  );
	// }else {

	//     d = await myFetch('https://gpts.ddaiai.com/open/gpts');
	// }

	const params = { pageNum: 1, pageSize: 20 };
	const [err, result] = await to(getGpts(params));
	if(err){
		console.log("err===",err)
	}else{
		gptsList.value = result.rows as unknown as gptsType[];
	}


	// gptsList.value = d.gpts as gptsType[];
	if(gptsList.value.length && gptsList.value.length > 3) {
		gptsFilterList.value = gptsList.value.slice(0, 4)
	}
}
const refresh = () => {
	gptsFilterList.value = []
	let num = gptsList.value[getRandowNum(0, gptsList.value.length - 1)]
	let num1 = gptsList.value[getRandowNum(0, gptsList.value.length - 1)]
	let num2 = gptsList.value[getRandowNum(0, gptsList.value.length - 1)]
	let num3 = gptsList.value[getRandowNum(0, gptsList.value.length - 1)]
	let arr = [num, num1, num2, num3]
	if(Array.from(new Set(arr)).length != 4) {
		refresh()
		return
	}
	gptsFilterList.value = [num, num1, num2, num3]
}
load()

</script>

<template>
	<NModal
		v-model:show="showModal"
		closable @on-after-leave=""
		:mask-closable="false"
		preset="dialog"
		title="公告详情"
		positive-text="我已知晓"
		@positive-click="handleClose"
	>
		<div v-html="modalContent"></div>
	</NModal>

	<div class="flex flex-col w-full h-full chat-content" :class="[isMobile? '' : 'chat-content-noMobile']">
		<!-- v-if="isMobile" -->
		<!-- <HeaderComponent
			:haveData="!!dataSources.length"
			:using-context="usingContext"
			@export="handleExport"
			@handle-clear="handleClear"
		/> -->

		<main class="flex-1 overflow-hidden">

			<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">

				<div
					id="image-wrapper"
					class="w-full max-w-screen-xl m-auto dark:bg-[#101014]"
					:class="[isMobile ? 'p-2' : 'p-4']"
				>
					<template v-if="!dataSources.length">
						<div v-if="homeStore.myData.session.notify" v-html="homeStore.myData.session.notify" class="text-neutral-300 mt-4">

						</div>

						<div class="gpts-box" v-else>
							<br>
							<br>
							<div  v-if="local!=='draw'">
<!--							<h1>{{ href }}</h1>-->
							<div class="annou" v-if="informContent.length" :style="{'margin-bottom': isMobile ? '15px' : '30px'}">
								<div class="ai-icon">
									<IconSvg icon="chatGPT" :width="isMobile ? '32px' : '64px'" :height="isMobile ? '32px' : '64px'"></IconSvg>
								</div>
								<div class="text" :style="{padding: isMobile? '22px 10px' : '22px 68px'}">
									<p class="title">{{ t('chat.annouce') }}</p>
									<!-- <p v-for="(item,index) in t('chat.annouceContent').split(';')" :key="index">{{ item }}</p> -->
									<div v-for="(item, index) in informContent.slice(0, 1)" :key="index" >
										<!-- <p style="margin-top: 10px; font-size: 18px">{{ item.noticeTitle }}</p> -->
										<div v-html="item.noticeContent"></div>
									</div>
								</div>
							</div>
							<div class="help" v-if="gptsFilterList && gptsFilterList.length">
								<div class="ai-icon">
									<IconSvg icon="chatGPT" :width="isMobile ? '32px' : '64px'" :height="isMobile ? '32px' : '64px'"></IconSvg>
								</div>
								<div class="text" :style="{padding: isMobile? '22px 10px' : '22px 68px', 'font-size': isMobile? '14px' : '16px', 'line-height': isMobile? '20px' : '28px'}">
									<p class="title">
										{{ t('chat.helpTitle') }}
									</p>
									<p v-for="(item,index) in t('chat.helpcontent').split(';')" :key="index">{{ item }}</p>
									<div class="gpts-list">
										<div class="refresh" @click="refresh">
											<IconSvg icon="refresh"></IconSvg>&nbsp;{{ t('chat.refresh') }}
										</div>
										<div v-for="v in gptsFilterList" :key="v.name" class="gpts-item" :style="{width: isMobile ? '100%' : 'calc(50% - 20px)', marginRight: '20px', padding: isMobile ? '5px 8px' : '14px 10px', 'margin-bottom': isMobile ? '8px' : '20px'}">
											<NImage :src="v.logo" :preview-disabled="true" lazy
															class="group-hover:scale-[130%] duration-300 shrink-0 overflow-hidden bg-base object-cover rounded-full bc-avatar w-[80px] h-[80px]" :style="{width: isMobile ? '23px' : '46px', height: isMobile ? '23px' : '46px'}">
												<template #placeholder>
													<div class="w-full h-full justify-center items-center flex"  >
														<SvgIcon icon="line-md:downloading-loop" class="text-[60px] text-green-300"   ></SvgIcon>
													</div>
												</template>
											</NImage>
											<div :style="{width: `calc(100% - ${isMobile ? '43px' : '66px'})`, float: 'left', marginLeft: '10px'}">
												<p class="info" :title="v.info"> {{ v.info }}</p>
												<p @click="goUseGpts(v)" class="name"> {{ t('chat.used') }} {{ v.name }}</p>
											</div>
										</div>
									</div>
								</div>
							</div>
						</div>
						</div>
						<!-- <div class="flex items-center justify-center mt-4 text-center text-neutral-300" v-else>
							<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
							<span>Aha~</span>
						</div> -->
					</template>

					<template v-else>
						<div>
							<Message
								v-for="(item, index) of dataSources"
								:key="index"
								:date-time="item.dateTime"
								:text="item.text"
								:inversion="item.inversion"
								:error="item.error"
								:loading="item.loading"
								@regenerate="onRegenerate(index)"
								@delete="handleDelete(index)"
								:chat="item"
								:index="index"
							/>
							<Message  v-if="ychat.text && !homeStore.myData.session.isCloseMdPreview"
												:key="dataSources.length" :inversion="true"
												:date-time="$t('mj.typing')"
												:chat="ychat"
												:text="ychat.text"
												:index="dataSources.length"
							/>
							<div class="sticky bottom-0 left-0 flex justify-center">
								<NButton v-if="loading" type="warning" @click="handleStop">
									<template #icon>
										<SvgIcon icon="ri:stop-circle-line" />
									</template>
									{{ t('common.stopResponding') }}
								</NButton>
							</div>
						</div>
					</template>
				</div>
			</div>
		</main>

		<footer :class="footerClass" class="footer-content" v-if="local!=='draw'">
			<div class="w-full max-w-screen-xl m-auto">
				<aiGptInput @handle-clear="handleClear" @export="handleExport" v-if="['gpt-4o-mini','gpt-3.5-turbo-16k'].indexOf(gptConfigStore.myData.model)>-1 || st.inputme "
										v-model:modelValue="prompt" :disabled="buttonDisabled"
										:searchOptions="searchOptions"  :renderOption="renderOption"
				/>
				<div class="flex items-center justify-between space-x-2" v-else>
					<!--
					<HoverButton v-if="!isMobile" @click="handleClear">
						<span class="text-xl text-[#4f555e] dark:text-white">
							<SvgIcon icon="ri:delete-bin-line" />
						</span>
					</HoverButton>
					<HoverButton v-if="!isMobile" @click="handleExport">
						<span class="text-xl text-[#4f555e] dark:text-white">
							<SvgIcon icon="ri:download-2-line" />
						</span>
					</HoverButton>
					<HoverButton @click="toggleUsingContext">
						<span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
							<SvgIcon icon="ri:chat-history-line" />
						</span>
					</HoverButton>
					-->

					<NAutoComplete v-model:value="prompt" :options="searchOptions" :render-label="renderOption">
						<template #default="{ handleInput, handleBlur, handleFocus }">
							<NInput
								ref="inputRef"
								v-model:value="prompt"
								type="textarea"
								:placeholder="placeholder"
								:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 8 }"
								@input="handleInput"
								@focus="handleFocus"
								@blur="handleBlur"
								@keypress="handleEnter"
							/>
						</template>
					</NAutoComplete>
					<NButton type="primary" :disabled="buttonDisabled" @click="handleSubmit">
						<template #icon>
              <span class="dark:text-black">
                <SvgIcon icon="ri:send-plane-fill" />
              </span>
						</template>
					</NButton>

				</div>
			</div>
		</footer>
	</div>

	<drawListVue />
	<aiGPT @finished="loading = false" />
	<AiSiderInput v-if="isMobile"  :button-disabled="false" />

</template>
