Files
k3GPT/main/ui/chat.aps
2025-11-19 19:43:02 +08:00

847 lines
66 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div x-data="chat" class="flex w-full my-2 rounded border">
<!-- 左边的 div -->
<div class="w-1/5 bg-zinc-900/10 h-[90vh] flex flex-col">
<div class="text-center my-2">
<button x-on:click="new0" type="button" class="cursor-pointer inline-flex whitespace-nowrap rounded bg-blue-700 px-2 py-2 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">新建对话</button>
<button x-show="$store.nav.qItems.length >0" x-on:click="gen_chat_baike" type="button" class="cursor-pointer inline-flex whitespace-nowrap rounded bg-green-700 px-2 py-2 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">创建对话列表词条</button>
</div>
<div class="flex-grow overflow-y-auto ">
<div class="font-bold text-sm m-2 text-sky-700">
<span x-text="$store.nav.ai_file.name"></span>
<button @click="pop_one_doc()" x-show="chat_files.length >0" class="rounded-full text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="取消当前对话文件" aria-label="取消当前对话文件" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" class="pointer-events-none w-4 h-4">
<path d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z"/>
</svg>
</button>
</div>
<div class="font-bold text-sm">当前对话列表:</div>
<ul>
<template x-for="(qitem, index) in $store.nav.qItems" :key="index">
<li class="ml-4 text-sm text-blue-700 my-2">
<span x-text="index+1"></span>.&nbsp;&nbsp;<a x-text="qitem.req" :href="'#QA'+index" @click="query=qitem.req"></a>
<button @click="del_chat(index)" class="rounded-full text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="删除此对话" aria-label="删除此对话" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" class="pointer-events-none w-4 h-4">
<path d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z"/>
</svg>
</button>
</li>
</template>
</ul>
</div>
</div>
<!-- 右边的 div -->
<div class="w-4/5 bg-zinc-50">
<div class="mx-4 flex flex-col h-[90vh]">
<!-- 对话的展示-->
<div id="chat_display" class="flex-grow overflow-y-auto">
<!-- 对话列表-->
<div class="mx-10">
<div class="flex flex-col gap-2 mx-4">
<!-- AI's Response -->
<div class="w-full mt-2 max-w-2xl border-zinc-300 bg-zinc-100 p-2 text-left dark:border-zinc-700 dark:bg-zinc-800 rounded border" >
<div class="flex items-center gap-2 text-neutral-900 dark:text-zinc-50">
<span class="flex size-8 items-center justify-center rounded-full bg-sky-700 text-white dark:bg-sky-600 dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="size-5">
<path d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.6 26.6 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.93.93 0 0 1-.765.935c-.845.147-2.34.346-4.235.346s-3.39-.2-4.235-.346A.93.93 0 0 1 3 9.219zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a25 25 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25 25 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135" />
<path d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2zM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5" />
</svg>
</span>
<span class="text-sm font-bold">Yi.AI</span>
</div>
<p class="text-pretty sm:pl-10 mt-4 sm:mt-0 text-sm text-neutral-600 dark:text-zinc-200">
你好,我是一个知识机器人,我可以帮你检索知识库并回答你的问题。
点击次按钮可以<button x-on:click="new_chat_win" type="button" class="cursor-pointer inline-flex whitespace-nowrap rounded bg-blue-700 p-1 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">打开一个新的聊天窗口</button>
,点击此按钮则可以<button x-on:click="his0" type="button" class="cursor-pointer inline-flex whitespace-nowrap rounded bg-sky-700 p-1 text-sm font-medium tracking-wide text-white transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">查看对话历史</button>
</p>
<!-- Actions -->
<div class="mt-2 flex items-center gap-2 sm:pl-10">
<button class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="Read Aloud" aria-label="Read Aloud" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M10.5 3.75a.75.75 0 0 0-1.264-.546L5.203 7H2.667a.75.75 0 0 0-.7.48A6.985 6.985 0 0 0 1.5 10c0 .887.165 1.737.468 2.52.111.29.39.48.7.48h2.535l4.033 3.796a.75.75 0 0 0 1.264-.546V3.75ZM16.45 5.05a.75.75 0 0 0-1.06 1.061 5.5 5.5 0 0 1 0 7.778.75.75 0 0 0 1.06 1.06 7 7 0 0 0 0-9.899Z"/>
<path d="M14.329 7.172a.75.75 0 0 0-1.061 1.06 2.5 2.5 0 0 1 0 3.536.75.75 0 0 0 1.06 1.06 4 4 0 0 0 0-5.656Z"/>
</svg>
</button>
<button @click="FileSelecterOpen=true" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="个人文件夹" aria-label="个人文件夹" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4 shrink-0" aria-hidden="true">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
<path d="M12 11v6"/>
<path d="M8 11v6"/>
<path d="M16 11v6"/>
</svg>
</button>
<button class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="More settings" aria-label="More settings" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/>
</svg>
</button>
</div>
</div>
<template x-for="(item, index) in $store.nav.Items" :key="index">
<div>
<!-- User's Chat -->
<div :id="'QA'+index" class="w-full ml-auto max-w-xl border-zinc-300 bg-zinc-100 p-2 text-left dark:border-zinc-700 dark:bg-zinc-800 rounded border" >
<div class="flex items-center gap-2 text-neutral-900 dark:text-zinc-50">
<span class="flex size-8 items-center justify-center rounded-full bg-blue-700 text-white dark:bg-sky-600 dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="size-5">
<path d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.6 26.6 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.93.93 0 0 1-.765.935c-.845.147-2.34.346-4.235.346s-3.39-.2-4.235-.346A.93.93 0 0 1 3 9.219zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a25 25 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25 25 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135" />
<path d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2zM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5" />
</svg>
</span>
<span x-text="item.req" class="text-sm">Alice Brown</span>
</div>
<p class="text-pretty sm:pl-10 mt-4 sm:mt-0 text-sm text-neutral-600 dark:text-zinc-200">
<button class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="Read Aloud" aria-label="Read Aloud" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M10.5 3.75a.75.75 0 0 0-1.264-.546L5.203 7H2.667a.75.75 0 0 0-.7.48A6.985 6.985 0 0 0 1.5 10c0 .887.165 1.737.468 2.52.111.29.39.48.7.48h2.535l4.033 3.796a.75.75 0 0 0 1.264-.546V3.75ZM16.45 5.05a.75.75 0 0 0-1.06 1.061 5.5 5.5 0 0 1 0 7.778.75.75 0 0 0 1.06 1.06 7 7 0 0 0 0-9.899Z"/>
<path d="M14.329 7.172a.75.75 0 0 0-1.061 1.06 2.5 2.5 0 0 1 0 3.536.75.75 0 0 0 1.06 1.06 4 4 0 0 0 0-5.656Z"/>
</svg>
</button>
<button x-on:click="copy_query(item.req)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="Copy" aria-label="Copy" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4" aria-hidden="true">
<path fill-rule="evenodd" d="M13.887 3.182c.396.037.79.08 1.183.128C16.194 3.45 17 4.414 17 5.517V16.75A2.25 2.25 0 0 1 14.75 19h-9.5A2.25 2.25 0 0 1 3 16.75V5.517c0-1.103.806-2.068 1.93-2.207.393-.048.787-.09 1.183-.128A3.001 3.001 0 0 1 9 1h2c1.373 0 2.531.923 2.887 2.182ZM7.5 4A1.5 1.5 0 0 1 9 2.5h2A1.5 1.5 0 0 1 12.5 4v.5h-5V4Z" clip-rule="evenodd"/>
</svg>
</button>
<button class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="More settings" aria-label="More settings" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/>
</svg>
</button>
</p>
</div>
<!-- AI's Response -->
<div x-show="item.rsp_show" class="mt-2 w-full border-zinc-300 bg-zinc-100 p-2 text-left dark:border-zinc-700 dark:bg-zinc-800 rounded border" >
<div class="flex items-center gap-2 text-neutral-900 dark:text-zinc-50">
<span class="flex size-8 items-center justify-center rounded-full bg-sky-700 text-white dark:bg-sky-600 dark:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="size-5">
<path d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.6 26.6 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.93.93 0 0 1-.765.935c-.845.147-2.34.346-4.235.346s-3.39-.2-4.235-.346A.93.93 0 0 1 3 9.219zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a25 25 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25 25 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135" />
<path d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2zM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5" />
</svg>
</span>
<span x-text="item.rsp" style="overflow-wrap: break-word;" class="text-sm font-bold">Pengu AI</span>
<button @click="show_info(index)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="上下文信息" aria-label="上下文信息" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/>
</svg>
</button>
</div>
<p x-bind:id="item.chat_id" :x-ref="item.chat_id" class="text-pretty sm:pl-10 mt-4 sm:mt-0 text-sm text-neutral-600 dark:text-zinc-200"></p>
<!-- 参考文件列表 -->
<ul x-show="is_gen && item.ctx.length >0 && item.show_file" class="text-pretty sm:pl-10 mt-4 sm:mt-0 text-sm">
<p class="text-sm text-sky-700"><br>以下为参考文件,单击可以选中文件,进行单个文件的对话:</p>
<template x-for="(doc,doc_index) in Array.from(new Map(item.ctx.map(doc => [doc.name, doc])).values());" :key="doc_index">
<li @click="add_one_doc(doc)" class="inline-flex bg-white text-black rounded-full p-2 m-2 hover:text-sky-700"><span x-text="doc_index+1"></span>.<span x-text="doc.name"></span></li>
</template>
</ul>
<!--数据分析文件列表 -->
<ul x-show="is_gen && item.chat_id in do_chat_files" class="text-pretty sm:pl-10 mt-4 sm:mt-0 text-sm">
<p class="text-sm text-sky-700"><br>以下是分析过程产生的文件,可以下载或切换对话文件:</p>
<template x-for="(doc,doc_index) in do_chat_files[item.chat_id]" :key="doc_index">
<li class="inline-flex bg-white text-black rounded-full p-2 m-2 hover:text-sky-700">
<span x-text="doc_index+1"></span>.<span @click="add_one_doc(doc)" x-text="doc.name"></span>
<button @click="window.open(`/api/fd?path=${doc.path}&filename=${doc.name}&base=${doc.base}`)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="下载" aria-label="下载" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="size-4" fill="currentColor">
<path d="M19 9h-4V3H9v6H5l7 7z"/>
<path d="M20 18H4v2h16z"/>
</svg>
</button>
</li>
</template>
</ul>
<!-- Actions -->
<div class="mt-2 flex items-center gap-2 sm:pl-10">
<button class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="Read Aloud" aria-label="Read Aloud" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M10.5 3.75a.75.75 0 0 0-1.264-.546L5.203 7H2.667a.75.75 0 0 0-.7.48A6.985 6.985 0 0 0 1.5 10c0 .887.165 1.737.468 2.52.111.29.39.48.7.48h2.535l4.033 3.796a.75.75 0 0 0 1.264-.546V3.75ZM16.45 5.05a.75.75 0 0 0-1.06 1.061 5.5 5.5 0 0 1 0 7.778.75.75 0 0 0 1.06 1.06 7 7 0 0 0 0-9.899Z"/>
<path d="M14.329 7.172a.75.75 0 0 0-1.061 1.06 2.5 2.5 0 0 1 0 3.536.75.75 0 0 0 1.06 1.06 4 4 0 0 0 0-5.656Z"/>
</svg>
</button>
<button x-on:click="copy_that(item.chat_id)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="Copy" aria-label="Copy" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-4" aria-hidden="true">
<path fill-rule="evenodd" d="M13.887 3.182c.396.037.79.08 1.183.128C16.194 3.45 17 4.414 17 5.517V16.75A2.25 2.25 0 0 1 14.75 19h-9.5A2.25 2.25 0 0 1 3 16.75V5.517c0-1.103.806-2.068 1.93-2.207.393-.048.787-.09 1.183-.128A3.001 3.001 0 0 1 9 1h2c1.373 0 2.531.923 2.887 2.182ZM7.5 4A1.5 1.5 0 0 1 9 2.5h2A1.5 1.5 0 0 1 12.5 4v.5h-5V4Z" clip-rule="evenodd"/>
</svg>
</button>
<button @click="new_baike(item.chat_id,index)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="创建词条" aria-label="创建词条" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="size-4">
<path d="M9.5 2.672a.5.5 0 1 0 1 0V.843a.5.5 0 0 0-1 0zm4.5.035A.5.5 0 0 0 13.293 2L12 3.293a.5.5 0 1 0 .707.707zM7.293 4A.5.5 0 1 0 8 3.293L6.707 2A.5.5 0 0 0 6 2.707zm-.621 2.5a.5.5 0 1 0 0-1H4.843a.5.5 0 1 0 0 1zm8.485 0a.5.5 0 1 0 0-1h-1.829a.5.5 0 0 0 0 1zM13.293 10A.5.5 0 1 0 14 9.293L12.707 8a.5.5 0 1 0-.707.707zM9.5 11.157a.5.5 0 0 0 1 0V9.328a.5.5 0 0 0-1 0zm1.854-5.097a.5.5 0 0 0 0-.706l-.708-.708a.5.5 0 0 0-.707 0L8.646 5.94a.5.5 0 0 0 0 .707l.708.708a.5.5 0 0 0 .707 0l1.293-1.293Zm-3 3a.5.5 0 0 0 0-.706l-.708-.708a.5.5 0 0 0-.707 0L.646 13.94a.5.5 0 0 0 0 .707l.708.708a.5.5 0 0 0 .707 0z"/>
</svg>
</button>
<button @click="new_baike_img(item.chat_id,index)" class="rounded-full p-1 text-neutral-600/75 hover:bg-zinc-900/10 hover:text-neutral-600 focus:outline-none focus-visible:text-neutral-600 focus-visible:zinc-300 focus-visible:outline-offset-0 focus-visible:outline-sky-700 active:bg-zinc-900/5 active:-outline-offset-2 dark:text-zinc-200/75 dark:hover:bg-zinc-50/10 dark:hover:text-zinc-200 dark:focus-visible:text-zinc-200 dark:focus-visible:outline-sky-600 dark:active:bg-zinc-50/5" title="图片词条" aria-label="图片词条" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4" aria-hidden="true">
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/>
</svg>
</button>
</div>
</div>
</div>
</template>
</ul>
</div>
</div>
</div>
<div class="flex mx-10 mt-2 gap-4">
<!-- Indigo-Blue -->
<button type="button" @click="mode='KG'" :style="mode === 'KG' ? 'color: white' : 'color: black'" class="bg-gradient-to-r from-indigo-600 to-blue-600 focus-visible:outline-indigo-600 dark:focus-visible:outline-indigo-600 rounded inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap px-4 py-2 text-xs tracking-wide transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:opacity-100 active:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-75">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" :fill="mode === 'KG' ? 'currentColor' : 'sky'" aria-hidden="true" class="size-4">
<path fill-rule="evenodd" d="M5 4a.75.75 0 0 1 .738.616l.252 1.388A1.25 1.25 0 0 0 6.996 7.01l1.388.252a.75.75 0 0 1 0 1.476l-1.388.252A1.25 1.25 0 0 0 5.99 9.996l-.252 1.388a.75.75 0 0 1-1.476 0L4.01 9.996A1.25 1.25 0 0 0 3.004 8.99l-1.388-.252a.75.75 0 0 1 0-1.476l1.388-.252A1.25 1.25 0 0 0 4.01 6.004l.252-1.388A.75.75 0 0 1 5 4ZM12 1a.75.75 0 0 1 .721.544l.195.682c.118.415.443.74.858.858l.682.195a.75.75 0 0 1 0 1.442l-.682.195a1.25 1.25 0 0 0-.858.858l-.195.682a.75.75 0 0 1-1.442 0l-.195-.682a1.25 1.25 0 0 0-.858-.858l-.682-.195a.75.75 0 0 1 0-1.442l.682-.195a1.25 1.25 0 0 0 .858-.858l.195-.682A.75.75 0 0 1 12 1ZM10 11a.75.75 0 0 1 .728.568.968.968 0 0 0 .704.704.75.75 0 0 1 0 1.456.968.968 0 0 0-.704.704.75.75 0 0 1-1.456 0 .968.968 0 0 0-.704-.704.75.75 0 0 1 0-1.456.968.968 0 0 0 .704-.704A.75.75 0 0 1 10 11Z" clip-rule="evenodd"/>
</svg>
快问快答
</button>
<!-- Green-Blue-Indigo -->
<button type="button" @click="mode='DS'" :style="mode === 'DS' ? 'color: white' : 'color: black'" class="bg-gradient-to-br from-green-500 via-blue-500 to-indigo-700 focus-visible:outline-indigo-500 dark:focus-visible:outline-indigo-500 rounded inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap px-4 py-2 text-xs font-medium tracking-wide transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:opacity-100 active:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-75">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" :fill="mode === 'DS' ? 'currentColor' : 'sky'" aria-hidden="true" class="size-4">
<path fill-rule="evenodd" d="M5 4a.75.75 0 0 1 .738.616l.252 1.388A1.25 1.25 0 0 0 6.996 7.01l1.388.252a.75.75 0 0 1 0 1.476l-1.388.252A1.25 1.25 0 0 0 5.99 9.996l-.252 1.388a.75.75 0 0 1-1.476 0L4.01 9.996A1.25 1.25 0 0 0 3.004 8.99l-1.388-.252a.75.75 0 0 1 0-1.476l1.388-.252A1.25 1.25 0 0 0 4.01 6.004l.252-1.388A.75.75 0 0 1 5 4ZM12 1a.75.75 0 0 1 .721.544l.195.682c.118.415.443.74.858.858l.682.195a.75.75 0 0 1 0 1.442l-.682.195a1.25 1.25 0 0 0-.858.858l-.195.682a.75.75 0 0 1-1.442 0l-.195-.682a1.25 1.25 0 0 0-.858-.858l-.682-.195a.75.75 0 0 1 0-1.442l.682-.195a1.25 1.25 0 0 0 .858-.858l.195-.682A.75.75 0 0 1 12 1ZM10 11a.75.75 0 0 1 .728.568.968.968 0 0 0 .704.704.75.75 0 0 1 0 1.456.968.968 0 0 0-.704.704.75.75 0 0 1-1.456 0 .968.968 0 0 0-.704-.704.75.75 0 0 1 0-1.456.968.968 0 0 0 .704-.704A.75.75 0 0 1 10 11Z" clip-rule="evenodd"/>
</svg>
深度思考
</button>
<button type="button" @click="mode='FA'" :style="mode === 'FA' ? 'color: white' : 'color: black'" class="bg-gradient-to-r from-purple-600 to-pink-600 focus-visible:outline-purple-600 dark:focus-visible:outline-purple-600 rounded inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap px-4 py-2 text-xs font-medium tracking-wide transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:opacity-100 active:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-75">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" :fill="mode === 'FA' ? 'currentColor' : 'sky'" aria-hidden="true" class="size-4">
<path fill-rule="evenodd" d="M5 4a.75.75 0 0 1 .738.616l.252 1.388A1.25 1.25 0 0 0 6.996 7.01l1.388.252a.75.75 0 0 1 0 1.476l-1.388.252A1.25 1.25 0 0 0 5.99 9.996l-.252 1.388a.75.75 0 0 1-1.476 0L4.01 9.996A1.25 1.25 0 0 0 3.004 8.99l-1.388-.252a.75.75 0 0 1 0-1.476l1.388-.252A1.25 1.25 0 0 0 4.01 6.004l.252-1.388A.75.75 0 0 1 5 4ZM12 1a.75.75 0 0 1 .721.544l.195.682c.118.415.443.74.858.858l.682.195a.75.75 0 0 1 0 1.442l-.682.195a1.25 1.25 0 0 0-.858.858l-.195.682a.75.75 0 0 1-1.442 0l-.195-.682a1.25 1.25 0 0 0-.858-.858l-.682-.195a.75.75 0 0 1 0-1.442l.682-.195a1.25 1.25 0 0 0 .858-.858l.195-.682A.75.75 0 0 1 12 1ZM10 11a.75.75 0 0 1 .728.568.968.968 0 0 0 .704.704.75.75 0 0 1 0 1.456.968.968 0 0 0-.704.704.75.75 0 0 1-1.456 0 .968.968 0 0 0-.704-.704.75.75 0 0 1 0-1.456.968.968 0 0 0 .704-.704A.75.75 0 0 1 10 11Z" clip-rule="evenodd"/>
</svg>
自由回答
</button>
<button type="button" @click="mode='NS'" :style="mode === 'NS' ? 'color: white' : 'color: black'" class="bg-gradient-to-br from-blue-600 to-purple-600 focus-visible:outline-blue-600 dark:focus-visible:outline-blue-600 rounded inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap px-4 py-2 text-xs font-medium tracking-wide transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 active:opacity-100 active:outline-offset-0 disabled:cursor-not-allowed disabled:opacity-75">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" :fill="mode === 'NS' ? 'currentColor' : 'sky'" aria-hidden="true" class="size-4">
<path fill-rule="evenodd" d="M5 4a.75.75 0 0 1 .738.616l.252 1.388A1.25 1.25 0 0 0 6.996 7.01l1.388.252a.75.75 0 0 1 0 1.476l-1.388.252A1.25 1.25 0 0 0 5.99 9.996l-.252 1.388a.75.75 0 0 1-1.476 0L4.01 9.996A1.25 1.25 0 0 0 3.004 8.99l-1.388-.252a.75.75 0 0 1 0-1.476l1.388-.252A1.25 1.25 0 0 0 4.01 6.004l.252-1.388A.75.75 0 0 1 5 4ZM12 1a.75.75 0 0 1 .721.544l.195.682c.118.415.443.74.858.858l.682.195a.75.75 0 0 1 0 1.442l-.682.195a1.25 1.25 0 0 0-.858.858l-.195.682a.75.75 0 0 1-1.442 0l-.195-.682a1.25 1.25 0 0 0-.858-.858l-.682-.195a.75.75 0 0 1 0-1.442l.682-.195a1.25 1.25 0 0 0 .858-.858l.195-.682A.75.75 0 0 1 12 1ZM10 11a.75.75 0 0 1 .728.568.968.968 0 0 0 .704.704.75.75 0 0 1 0 1.456.968.968 0 0 0-.704.704.75.75 0 0 1-1.456 0 .968.968 0 0 0-.704-.704.75.75 0 0 1 0-1.456.968.968 0 0 0 .704-.704A.75.75 0 0 1 10 11Z" clip-rule="evenodd"/>
</svg>
联网搜索
</button>
</div>
<!-- 输入框 -->
<div class="flex w-full flex-col gap-2 mb-4 mt-2">
<div class="relative w-full">
<label class="sr-only">ai prompt</label>
<!-- 文件上传-->
<input x-ref="fileInput" @input="upload_file" type="file" multiple hidden class="w-full overflow-clip rounded border border-red-700 bg-zinc-100/50 text-sm text-red-700 file:mr-4 file:cursor-pointer file:border-none file:bg-zinc-100 file:px-4 file:py-2 file:font-medium file:text-neutral-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 disabled:cursor-not-allowed disabled:opacity-75 dark:bg-zinc-800/50 dark:file:bg-zinc-800 dark:file:text-zinc-50 dark:focus-visible:outline-sky-600" />
<svg @click="$refs.fileInput.click()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" class="absolute left-3 top-1/2 size-6 cursor-pointer -translate-y-1/2 fill-blue-700 dark:fill-sky-600">
<path fill-rule="evenodd" d="M10.5 3.75a6 6 0 0 0-5.98 6.496A5.25 5.25 0 0 0 6.75 20.25H18a4.5 4.5 0 0 0 2.206-8.423 3.75 3.75 0 0 0-4.133-4.303A6.001 6.001 0 0 0 10.5 3.75Zm2.03 5.47a.75.75 0 0 0-1.06 0l-3 3a.75.75 0 1 0 1.06 1.06l1.72-1.72v4.94a.75.75 0 0 0 1.5 0v-4.94l1.72 1.72a.75.75 0 1 0 1.06-1.06l-3-3Z" clip-rule="evenodd"/>
</svg>
<input x-show="one" x-model="query" x-on:input.debounce.100ms="query_len" x-on:keydown.enter="gen" type="text" class="w-full border-outline bg-zinc-100 border border-zinc-300 rounded px-2 py-2 pl-10 pr-24 text-sm text-neutral-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 disabled:cursor-not-allowed disabled:opacity-75 dark:border-zinc-700 dark:bg-zinc-800/50 dark:text-zinc-200 dark:focus-visible:outline-sky-600" value="" name="prompt" placeholder="Ask AI ..." />
<textarea id="aiPromt" x-show="!one" rows="5" x-model="query" x-on:input.debounce.100ms="query_len" type="text" class="w-full border-outline bg-zinc-100 border border-zinc-300 rounded px-2 py-2 pl-10 pr-24 text-sm text-neutral-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 disabled:cursor-not-allowed disabled:opacity-75 dark:border-zinc-700 dark:bg-zinc-800/50 dark:text-zinc-200 dark:focus-visible:outline-sky-600" value="" name="prompt" placeholder="Ask AI ..." ></textarea>
<button type="button" x-show="is_gen" x-on:click="gen" class="absolute right-3 top-1/2 -translate-y-1/2 cursor-pointer bg-sky-700 rounded px-2 py-1 text-xs tracking-wide text-white transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">Generate</button>
<button type="button" x-show="!is_gen" x-on:click="stop" class="absolute right-3 top-1/2 -translate-y-1/2 cursor-pointer bg-blue-700 rounded px-2 py-1 text-xs tracking-wide text-white transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-700 active:opacity-100 active:outline-offset-0 dark:bg-sky-600 dark:text-white dark:focus-visible:outline-sky-600">Stop</button>
</div>
</div>
</div>
</div>
<!-- 弹出框 历史对话-->
<div>
<template x-if="HisOpen">
<div x-ref="his" x-cloak x-transition.opacity.duration.200ms x-trap.inert.noscroll="HisOpen" class="fixed inset-0 z-30 flex items-end justify-center bg-black/20 px-4 py-2 backdrop-blur-md sm:items-center lg:p-8" role="dialog" aria-modal="true" aria-labelledby="infoModalTitle">
<!-- Modal Dialog -->
<div x-show="HisOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="flex w-full h-full flex-col gap-1 overflow-hidden rounded border border-zinc-300 bg-zinc-50 text-neutral-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">
<!-- Dialog Header -->
<div class="flex items-center justify-between border-b border-zinc-300 bg-zinc-100/60 px-4 py-2 dark:border-zinc-700 dark:bg-zinc-900/20">
<div class="flex items-center justify-center rounded-full bg-sky-700/20 text-sky-700 p-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-6" aria-hidden="true">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd" />
</svg>
历史会话
</div>
<button @click="HisOpen=false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="px-4 py-2 text-center h-full overflow-y-auto">
<div alp-unit="chat_history.html"></div>
</div>
</div>
</div>
</template>
<template x-if="AIEditorOpen">
<div x-ref="his" x-cloak x-transition.opacity.duration.200ms x-trap.inert.noscroll="AIEditorOpen" @keydown.esc.window="close_aieditor" class="fixed inset-0 z-30 flex items-end justify-center bg-black/20 px-4 py-2 backdrop-blur-md sm:items-center lg:p-8" role="dialog" aria-modal="true" aria-labelledby="infoModalTitle">
<!-- Modal Dialog -->
<div x-show="AIEditorOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="flex w-full h-full flex-col gap-1 overflow-hidden rounded border border-zinc-300 bg-zinc-50 text-neutral-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">
<!-- Dialog Header -->
<div class="flex items-center justify-between border-b border-zinc-300 bg-zinc-100/60 px-4 py-2 dark:border-zinc-700 dark:bg-zinc-900/20">
<div class="flex items-center justify-center rounded-full bg-sky-700/20 text-sky-700 p-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-6" aria-hidden="true">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd" />
</svg>
百科词条AI编辑器
</div>
<button @click="AIEditorOpen=false" aria-label="close modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- Dialog Body -->
<div class="px-4 py-2 text-center h-full">
<iframe :src="aieditor_id" class="w-full h-full overflow-hidden"></iframe>
</div>
</div>
</div>
</template>
</div>
<!-- Info 上下文的信息提示-->
<div x-show="Info" class="fixed top-10 left-0 right-0 z-30 w-full mx-auto max-w-2xl flex items-center justify-center rounded border border-sky-700 bg-zinc-50 text-neutral-600 dark:bg-zinc-900 dark:text-zinc-200" role="alert">
<div class="flex w-full items-center gap-2 bg-sky-700/10 p-4">
<div class="bg-sky-700/15 text-sky-700 rounded-full p-1" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-6" aria-hidden="true">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.253a.25.25 0 0 1 .244.304l-.459 2.066A1.75 1.75 0 0 0 10.747 15H11a.75.75 0 0 0 0-1.5h-.253a.25.25 0 0 1-.244-.304l.459-2.066A1.75 1.75 0 0 0 9.253 9H9Z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-2 max-h-[80vh] overflow-y-auto">
<h3 class="text-sm font-semibold text-sky-700">上下文信息如下:</h3>
<p class="text-xs font-medium sm:text-sm"></p>
<ul class="mt-2 list-inside list-disc pl-2 text-xs font-medium sm:text-sm">
<template x-for="(item,index) in fItems" :key="index">
<li><strong x-text="index+1">No.</strong>.&nbsp;&nbsp;<strong x-text="item.name">文件名</strong> 长度: [<span x-text="item.size" class="text-blue-700">长度</span>]
<p class="text-sky-700">来源: <span x-text="item.base"></span> &nbsp;&nbsp;路径: <span x-text="item.path"></span></p>
<p x-html="marked.parse(item.ctx)">内容</p></li>
</template>
</ul>
</div>
<button @click="Info=false" class="ml-auto" aria-label="dismiss alert">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="2.5" class="w-4 h-4 shrink-0">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<!-- 选择文件窗口-->
<div x-show="FileSelecterOpen" id="file_selector" class="fixed top-10 left-0 right-0 z-30 mx-auto max-w-3xl w-full overflow-hidden rounded border border-sky-700 bg-zinc-50 text-neutral-600 dark:bg-zinc-900 dark:text-zinc-200" role="alert">
<div id="file_selector_m" class="flex moved w-full items-center gap-2 bg-sky-700/90 p-2">
<div class="ml-2">
<h3 class="text-sm font-semibold text-white">个人文件夹</h3>
</div>
<button @click="FileSelecterOpen=false" class="ml-auto" aria-label="dismiss alert">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="2.5" class="w-4 h-4 shrink-0">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<!-- body-->
<div class="flex w-full items-center gap-2 bg-sky-700/10 p-2">
<template x-if="FileSelecterOpen">
<div id="kg_select" alp-unit="kg_select.aps" class="w-full overflow-hidden"></div>
</template>
</div>
</div>
</div>
<script>
function chat(){
return {
query:"",
mode:"KG", //KG-知识库NS-全网搜索,FA-自由回答,DS-深度思考
HisOpen: false, //历史对话框
AIEditorOpen: false, // 百科创作对话框
aieditor_id:"", //百科id
eventSource: "", //对话流
is_gen: true, //生成模式
Info: false, // 显示上下文
fItems:[], //上下文信息
one:true, //一行文本输入
baike_id:0, //新增词条
do_chat_files:{}, //对话过程中产生的文件,主要是数据分析
chat_files:[], //保留对话的文件的记录
ai_file:{}, // 默认的上传文件
kagent:{}, // 具体配置
FileSelecterOpen:false, //显示个人文件夹
people_files:"",
init(){
var doc = localStorage.getItem("chat");
if (doc){
this.$store.nav.ai_file = JSON.parse(doc);
this.ai_file = this.$store.nav.ai_file
this.push_item({chat_id:"",req:"你之前上传了文件: "+this.$store.nav.ai_file.name+", 可以继续对话",rsp:"",rsp_show:false});
}
this.people_files="个人文件夹/"+this.$store.nav.username;
//动态加载,AI对话框
this.$watch('FileSelecterOpen',value => {
if (value){
this.$nextTick(() => {
var dom = document.getElementById("kg_select")
scan_alp_units(dom);
});
}
});
},
query_len(){
if (this.query.length >45){
this.one=false;
/*
this.$nextTick(() => {
const textarea = document.getElementById("aiPromt");
textarea.focus(); // 必须先聚焦,否则某些浏览器不生效
console.info("激活多行输入");
// 获取当前光标位置或选中的起始和结束位置
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
textarea.setSelectionRange(start, end);
});
*/
if (this.query.length >300){
const aiPromt = document.getElementById("aiPromt");
aiPromt.rows="10";
}
if (this.query.length >1000){
const aiPromt = document.getElementById("aiPromt");
aiPromt.rows="15";
}
}
},
new0(){ //新建对话
this.$store.nav.qItems=[];
this.$store.nav.Items=[];
this.$store.nav.ai_file={};
this.$store.nav.ai_tips="你好,我可以帮你检索知识库并回答你的问题。请问我有什么可以帮助你的?";
this.is_gen = true;
this.one = true;
},
new_chat_win(){
window.open("/ui/index.html?tab=comments", '_blank');
},
his0(){ //历史对话
this.HisOpen = true;
//dom 更新后加载
this.$nextTick(() => {
scan_alp_units(this.$refs.his);
});
},
copy_query(query){ //复制查询
this.query = query;
this.query_len()
},
gen_chat_baike(){//生成对话列表的百科
var content="";
const today = new Date();
if (Object.keys(this.$store.nav.ai_file).length>=0 & this.mode=="KG" ) {
content=`<h1>K3GPT数据分析智能体</h1>
<h3>基于${this.$store.nav.ai_file.name}进行问答</h3>
<p>制作日期: ${getFormattedDate(today)}</p>`;
}else{
content=`<h1>K3GPT知识对话智能体</h1>
<h3>基于${this.$store.nav.qItems[0].req.slice(0,20)}的对话列表进行生成</h3>
<p>制作日期: ${getFormattedDate(today)}</p>`;
}
//目录
const catalogs = this.$store.nav.qItems.map(item=>item.req);
content +=`<p>[catalogs]<pre><code>${JSON.stringify(catalogs)}</code></pre></p>`;
//问题
for(var i=0;i<this.$store.nav.qItems.length;i++){
let chat_id = this.$store.nav.qItems[i].chat_id;
const messagesDiv = document.getElementById(chat_id);
let rsp = messagesDiv.innerHTML;
console.info(rsp);
let end = rsp.lastIndexOf('padding:5px;">');
rsp = rsp.slice(end+'padding:5px;">'.length,-12);
//content += '<p><span style="color: blue; font-weight: bold;">'+this.qItems[i].req+"</span></p>"+rsp;
content += `<guide>${this.$store.nav.qItems[i].req}</guide>`;
content += gen_ppt_slides(this.$store.nav.qItems[i].req,rsp,chat_id)
}
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: "对话列表-"+this.$store.nav.qItems[0].req.slice(0,20),
catalog: "词条",
html: content
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike', newItem)
.then(response =>{
this.baike_id = response.data.id;
this.AIEditorOpen=true;
this.aieditor_id="create.html?id="+this.baike_id;
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
show_info(index){ //显示上下文
this.Info=true;
this.fItems = this.$store.nav.Items[index].ctx;
},
copy_that(chat_id){
const messagesDiv = document.getElementById(chat_id);
let rsp = messagesDiv.innerHTML;
rsp = rsp.replace("<think>","<p>").replace("</think>","</p>");
copyToClipboard(rsp);
},
new_baike(chat_id,index){ //新建百科词条
const messagesDiv = document.getElementById(chat_id);
let rsp = messagesDiv.innerHTML;
let end = rsp.lastIndexOf('padding:5px;">');
rsp = rsp.slice(end+'padding:5px;">'.length,-12);
var content="";
if (Object.keys(this.$store.nav.ai_file).length>=0 & this.mode=="KG" ) {
content = gen_ppt(this.$store.nav.ai_file.name,this.$store.nav.Items[index].req,rsp,chat_id);
}else{
content = rsp;
}
// 数据对象,代表要发送的数据
const newItem = {
id: 0,
title: this.$store.nav.Items[index].req.slice(0,30),
catalog: "词条",
html: content
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike', newItem)
.then(response =>{
let baike_id = response.data.id;
this.AIEditorOpen=true;
this.aieditor_id="create.html?id="+baike_id;
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
async new_baike_img(chat_id,index){ //新建百科词条,用图表img的方式
const messagesDiv = document.getElementById(chat_id);
let rsp = messagesDiv.innerHTML;
let end = rsp.lastIndexOf('padding:5px;">');
rsp = rsp.slice(end+'padding:5px;">'.length,-12);
var html = await gen_ppt_by_img(this.$store.nav.ai_file.name,this.$store.nav.Items[index].req,rsp,chat_id);
// 数据对象,代表要发送的数据
const newItem = {
id: 0,
title: this.$store.nav.Items[index].req.slice(0,20),
catalog: "词条",
html: html
};
console.info(newItem);
// 使用 axios 发送 POST 请求
axios.post('/api/baike', newItem)
.then(response =>{
let baike_id = response.data.id;
this.AIEditorOpen=true;
this.aieditor_id="create.html?id="+baike_id;
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
stop(){
this.eventSource.close();
this.is_gen = true;
this.one=true;
},
gen(){
this.is_gen = false;
this.$store.nav.push_item({chat_id:"",req:this.query,rsp:"",rsp_show:false});
var query=this.query;
if (this.query.length >100){
query = this.query.slice(0,100)+"...";
}
this.$store.nav.ai_file = this.ai_file;
//
if (Object.keys(this.$store.nav.ai_file).length>=0 & this.mode=="KG" ) {
//单个文档对话
// 数据对象,代表要发送的数据
const newItem = {
question: this.query,
file: this.$store.nav.ai_file.name,
base: this.$store.nav.ai_file.base,
path: String(this.$store.nav.ai_file.path),
history: this.$store.nav.qItems.map(item => item.req),
};
// 使用 axios 发送 POST 请求
axios.post('/api/chat_one_doc', newItem)
.then(response =>{
rsp = response.data;
this.$store.nav.update_last_item(rsp.chat_id,`搜索到${rsp.count}个相关信息,正在整理中...`,rsp.ctx);
this.$store.nav.push_qitem({chat_id:rsp.chat_id,req:query});
// 创建一个EventSource实例连接到服务器发送的事件流
this.eventSource = new EventSource('/api/chat/'+rsp.chat_id);
update_chat(this.eventSource,rsp.chat_id,this);
const div = document.getElementById("chat_display");
div.scrollTop = div.scrollHeight;
})
.catch(error => {
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}else{
// 数据对象,代表要发送的数据
const newItem = {
question: this.query,
ai_mode: this.mode,
history: this.$store.nav.qItems.map(item => item.req),
};
// 使用 axios 发送 POST 请求
axios.post('/api/chat_search', newItem)
.then(response =>{
rsp = response.data;
if (["KG","NS"].includes(this.mode)){
this.$store.nav.update_last_item(rsp.chat_id,`搜索到${rsp.count}个相关信息,正在整理中...`,rsp.ctx);
}else{
this.$store.nav.update_last_item(rsp.chat_id,`正在思考中...`,rsp.ctx);
}
this.$store.nav.push_qitem({chat_id:rsp.chat_id,req:query});
// 创建一个EventSource实例连接到服务器发送的事件流
this.eventSource = new EventSource('/api/chat/'+rsp.chat_id);
update_chat(this.eventSource,rsp.chat_id,this);
const div = document.getElementById("chat_display");
div.scrollTop = div.scrollHeight;
})
.catch(error => {
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}
this.query="";
this.one=true;
const div = document.getElementById("chat_display");
div.scrollTop = div.scrollHeight;
},
add_one_doc(doc){ //选中一个文档
//保存原来的值
this.chat_files.push(this.$store.nav.ai_file);
this.$store.nav.ai_file= {name:doc.name,path:doc.path,base:doc.base};
this.push_item({chat_id:"",req:"你选择了文件: "+this.$store.nav.ai_file.name+", 可以继续对话",rsp:"",rsp_show:false});
},
pop_one_doc(){
//弹出一个
this.$store.nav.ai_file= this.chat_files.pop();
},
del_chat(index){//删除对话列表中的对话
this.$store.nav.qItems.splice(index,1);
},
upload_file(){
const file = this.$refs.fileInput.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
formData.append("curpath","文档");
try {
axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then( response =>{
var doc = response.data;
if (doc.errno === 1) {
alert(doc.message);
}else{
this.$store.nav.ai_file=doc.file;
//this.$store.nav.ai_tips=`你好,你选定了《${doc.file.name}》文件,我可以根据文件内容回答你的问题。如文章的主要内容?文章的大纲?等`;
this.$store.nav.push_item({chat_id:"",req:`你上传了《${doc.file.name}》文件,我可以根据文件内容回答你的问题。如文章的主要内容?文章的大纲?等`,rsp:"",rsp_show:false});
// 保存本地缓存
localStorage.setItem("chat", JSON.stringify(doc.file))
}
})
} catch (error) {
console.error('Error:', error);
alert('An error occurred while uploading the file.');
}
}// upload_file 上传文件
}
}
var chart_index=0;
var chart_datas={};//存储对话的图表,表格等数据
var chart_ids={}; //存储对话的不表的div的id
//流式更新对话
function update_chat(eventSource,chat_id,fun){
fun.is_gen = false;
var old_think="";
//分块更新
var ResponseDiv = null;
var messagesDiv = document.createElement('div');
chart_datas[chat_id] ={}; //图表数据
chart_ids[chat_id]={}; //图表div 的id
var do_files=[];
// 监听消息事件,将接收到的数据显示在网页上
eventSource.onmessage = function(event) {
//首次创建
if (ResponseDiv==null){
ResponseDiv = document.getElementById(chat_id);
ResponseDiv.appendChild(messagesDiv);
}
const message = JSON.parse(event.data);
if ("type" in message){ //完整消息
if (["do_group_count","do_group_agg","do_fields_agg"].includes(message.type)){
try {
let rsp = JSON.parse(message.rsp);
if ("excel" in rsp){
do_files.push({"name":rsp["excel"].split(/[\\/]/).pop(),"path":rsp["excel"],"base":"文件中心"});
}
var think_mk=`<div style="position: relative; height:300px; width:700px; margin-bottom:60px;">
<canvas id="myChart_${chart_index}"></canvas>
</div>`;
messagesDiv.innerHTML = old_think + think_mk;
//console.info(message)
const r = draw_chart("myChart_"+chart_index,rsp,message.type);
chart_datas[chat_id][r["title"]] = r["data"];
chart_ids[chat_id][r["title"]] = "myChart_"+chart_index;
chart_index ++;
} catch (error) {
think_mk = "图表出错:"+error+"<br>"+message.rsp;
messagesDiv.innerHTML = old_think + think_mk;
}
}else if (["do_filter","do_ext_tags"].includes(message.type)){
try {
let rsp = JSON.parse(message.rsp);
if ("excel" in rsp){
do_files.push({"name":rsp["excel"].split(/[\\/]/).pop(),"path":rsp["excel"],"base":"文件中心"});
}
var think_mk=`<div id="myChart_${chart_index}"
style="position: relative; height:300px; width:700px; background-color: white;
border-radius: 5px; overflow: auto; margin:5px;">
</div>`;
messagesDiv.innerHTML = old_think + think_mk;
//console.info(message)
const r = draw_table("myChart_"+chart_index,rsp,message.type);
chart_datas[chat_id]["Table_"+chart_index] = r;
chart_index ++;
} catch (error) {
think_mk = "表格出错:"+error+"<br>"+message.rsp;
messagesDiv.innerHTML = old_think + think_mk;
}
}else{
think_mk = marked.parse(message.rsp);
messagesDiv.innerHTML = old_think + think_mk;
}
}else if (message.rsp.indexOf("<think>")==0){
var end = message.rsp.indexOf("</think>");
if (end==-1){ //思考还未结束
var think_mk = marked.parse(message.rsp.slice(7));
messagesDiv.innerHTML = old_think + think_mk;
//messagesDiv.insertAdjacentHTML("beforeend",think_mk);
}else{
var think_mk = marked.parse(message.rsp.slice(7,end));
var result= marked.parse(message.rsp.slice(end+8));
if (result!=""){
var think_all=`${think_mk}<div style="color: white; background-color: rgb(3 105 161 / 0.7); border-radius: 5px; margin-bottom: 5px; padding:5px;">${result}</div>`;
messagesDiv.innerHTML = old_think+think_all;
}
}
}else if(message.rsp.indexOf("<new>")==0){
//新的一个消息,新的一个层
messagesDiv = document.createElement('div');
ResponseDiv.appendChild(messagesDiv);
}else{
var think_all=`<div style="color: white; background-color: rgb(3 105 161 / 0.7); border-radius: 5px; margin-bottom: 5px; padding:5px;">${marked.parse(message.rsp)}</div>`;
messagesDiv.innerHTML = old_think+ think_all;
}
//自动滚动
const div = document.getElementById("chat_display");
div.scrollTop = div.scrollHeight;
};
// 监听错误事件
eventSource.onerror = function(error) {
fun.is_gen = true;
console.info(chat_id+" 回答结束");
if (do_files.length >0){
fun.do_chat_files[chat_id]=do_files;
console.info(do_files);
}
//结束后滚动
const div = document.getElementById("chat_display");
div.scrollTop = div.scrollHeight;
if (eventSource.readyState != EventSource.CLOSED){
eventSource.close(); // 关闭连接
}
};
}
</script>