Files
k3GPT/main/ui/create.html
2025-11-19 19:43:15 +08:00

1052 lines
56 KiB
HTML
Raw 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.

<!DOCTYPE html>
<html>
<link href="wang/wangedit.css" rel="stylesheet" />
<style>
#editorwrapper {
border: 1px solid #ccc;
z-index: 10; /* 按需定义 */
}
#toolbar-container {
border-bottom: 1px solid #ccc;
}
</style>
<style>
/* WebKit 浏览器的滚动条 */
::-webkit-scrollbar {
width: 4px; /* 滚动条宽度 */
height: 10px;
}
::-webkit-scrollbar-track {
background: #f1f1f1; /* 轨道背景色 */
}
::-webkit-scrollbar-thumb {
background: #888; /* 滚动条颜色 */
border-radius: 4px; /* 圆角 */
}
::-webkit-scrollbar-thumb:hover {
background: #555; /* 滚动条悬停时的颜色 */
}
html, body {
overflow: hidden;
}
/* 基础样式 */
h1, h2, h3, h4, h5 {
font-weight: bold;
line-height: 1.2;
margin-top: 1.5em;
margin-bottom: 0.5em;
}
</style>
<!--<script src="https://cdn.tailwindcss.com"></script>-->
<link rel="stylesheet" href="tw.k3gpt.css">
<script src="js/axios.min.js"></script>
<script src="js/marked.js"></script>
<script defer src="js/alpine.js"></script>
<script defer src="js/alp_unit.js"></script>
<body>
<!-- 编辑器的主窗口 -->
<div x-data="$store.ai_job" x-init="init2" class="overflow-hidden">
<!-- 查询器 四角弧形的矩形容器 -->
<div class="flex rounded-lg bg-white shadow-lg p-2 space-x-4 mb-4">
<!-- 横向排列的四个元素 -->
<!--<div class="flex items-center justify-center text-neutral-600 dark:text-zinc-200">标题</div>-->
<div class="relative flex w-full max-w-xs flex-col gap-1 text-neutral-600 dark:text-zinc-200">
<input x-model="title" type="text" class="w-full rounded border border-zinc-300 bg-zinc-100 py-2 pl-2 pr-2 text-sm 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:focus-visible:outline-sky-600" name="search" placeholder="输入标题" aria-label="search"/>
</div>
<!--<div class="flex items-center justify-center text-neutral-600 dark:text-zinc-200">分类</div>-->
<div class="relative flex w-full max-w-s1 flex-col gap-1 text-neutral-600 dark:text-zinc-200">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="absolute pointer-events-none right-2 top-2 h-5 w-5">
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
</svg>
<select id="catalog" x-model="catalog" class="w-full appearance-none rounded border border-zinc-300 bg-zinc-100 px-4 py-2 text-sm 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:focus-visible:outline-sky-600">
<template x-for="(item,index) in catalogs" :key="index">
<option x-text="item" :selected="catalog==item">词条</option>
</template>
</select>
</div>
<button id="save" @click="do_save" type="button" class="cursor-pointer whitespace-nowrap rounded bg-sky-700 px-4 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 id="save_text" @click="do_save_text" type="button" class="cursor-pointer whitespace-nowrap rounded bg-zinc-200 px-4 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 @click="window.open('view.html?id='+baike_id)" type="button" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded bg-blue-700 px-4 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 @click="gen_word" type="button" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded bg-sky-700 px-4 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">
DOC
</button>
<button @click="gen_pdf" type="button" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded bg-sky-700 px-4 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">
PDF
</button>
<button @click="gen_ppt" type="button" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded bg-green-700 px-4 py-2 text-sm font-medium tracking-wide text-white transition 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">
PPT
<svg @click="gen_ppt2($event)" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 fill-white dark:fill-white hover:bg-zinc-900/10" fill="currentColor">
<path fill-rule="evenodd" d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z" clip-rule="evenodd" />
</svg>
</button>
<button @click="gen_poster" type="button" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded bg-green-700 px-4 py-2 text-sm font-medium tracking-wide text-white transition 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">
海报
<svg @click="gen_poster2($event)" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 fill-white dark:fill-white hover:bg-zinc-900/10" fill="currentColor">
<path fill-rule="evenodd" d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z" clip-rule="evenodd" />
</svg>
</button>
<button @click="successModalIsOpen=true" class="rounded-full p-2.5 hover:text-green-700 bg-zinc-900/10 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-5 shrink-0" aria-hidden="true">
<path fill-rule="evenodd" d="M10 2c-2.236 0-4.43.18-6.57.524C1.993 2.755 1 4.014 1 5.426v5.148c0 1.413.993 2.67 2.43 2.902 1.168.188 2.352.327 3.55.414.28.02.521.18.642.413l1.713 3.293a.75.75 0 0 0 1.33 0l1.713-3.293a.783.783 0 0 1 .642-.413 41.102 41.102 0 0 0 3.55-.414c1.437-.231 2.43-1.49 2.43-2.902V5.426c0-1.413-.993-2.67-2.43-2.902A41.289 41.289 0 0 0 10 2ZM6.75 6a.75.75 0 0 0 0 1.5h6.5a.75.75 0 0 0 0-1.5h-6.5Zm0 2.5a.75.75 0 0 0 0 1.5h3.5a.75.75 0 0 0 0-1.5h-3.5Z" clip-rule="evenodd"/>
</svg>
</button>
</div>
<!-- 进度条-->
<template x-if="progressbar">
<div class="flex h-4 w-full overflow-hidden rounded-radius bg-slate-100 dark:bg-surface-dark-alt" role="progressbar" aria-label="default progress bar" x-bind:aria-valuenow="currentVal" x-bind:aria-valuemin="minVal" x-bind:aria-valuemax="maxVal">
<div class="h-full rounded-radius bg-sky-700 dark:bg-primary-dark" x-bind:style="`width: ${calcPercentage(minVal, maxVal, currentVal)}%`"></div>
</div>
</template>
<!-- 编辑器部分 -->
<div id="editor—wrapper">
<div id="toolbar-container"><!-- 工具栏 --></div>
<div id="editor-container" class="h-[75vh]"><!-- 编辑器 --></div>
</div>
<!-- AI创作窗口 -->
<template x-if="modalIsOpen">
<div x-cloak x-transition.opacity.duration.200ms x-trap.inert.noscroll="modalIsOpen" @keydown.esc.window="modalIsOpen = false" class="fixed inset-0 z-50 flex items-end justify-center p-4 sm:items-center lg:p-4" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog-->
<div x-show="modalIsOpen" 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-3/5 max-h-[80vh] flex-col gap-4 overflow-hidden rounded-xl border border-slate-300 bg-white text-slate-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300">
<!-- Dialog Header -->
<div class="flex items-center justify-between border-b border-slate-300 bg-slate-100/60 px-2 dark:border-slate-700 dark:bg-slate-900/20">
<h4 id="defaultModalTitle" class="font-semibold tracking-wide text-black dark:text-white">AI创作</h4>
<!-- 搜索框-->
<div class="flex justify-center w-full max-w-md gap-2 border-zinc-300 dark:border-zinc-700" role="tablist" aria-label="tab options">
<div class="relative py-2 flex w-full max-w-md flex-col gap-1 text-neutral-600 dark:text-zinc-200">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="absolute left-2 top-1/2 size-5 -translate-y-1/2 text-neutral-600/50 dark:text-zinc-200/50" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/>
</svg>
<input x-model="search" x-on:input.debounce.900ms="fetchSomething()" placeholder="搜索全站文档,选定一个文档,来进行精准对话" type="search" class="w-full border border-zinc-300 rounded bg-zinc-50 px-2 py-1.5 pl-9 text-sm 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-900/50 dark:focus-visible:outline-sky-600" name="search" aria-label="Search" placeholder="Search"/>
</div>
</div>
<button @click="modalIsOpen = 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>
<!-- 创作完成后的方式-->
<div class="flex justify-center gap-1">
<!-- 下拉框-->
<div x-data="{
options: [
{
value: 'AI续写',
label: 'AI续写',
},
{
value: 'AI摘要',
label: 'AI摘要',
},
{
value: 'AI大纲',
label: 'AI大纲',
},
{
value: 'AI丰富',
label: 'AI丰富',
},
{
value: 'AI优化',
label: 'AI优化',
},
{
value: '拼写检查',
label: '拼写检查',
},
{
value: '智能翻译',
label: '智能翻译',
},
{
value: '指令模式',
label: '指令模式',
},
],
isOpen: false,
openedWithKeyboard: false,
selectedOption: null,
setSelectedOption(option) {
this.selectedOption = option
this.isOpen = false
this.openedWithKeyboard = false
this.$refs.hiddenTextField.value = option.value
},
highlightFirstMatchingOption(pressedKey) {
const option = this.options.find((item) =>
item.label.toLowerCase().startsWith(pressedKey.toLowerCase()),
)
if (option) {
const index = this.options.indexOf(option)
const allOptions = document.querySelectorAll('.combobox-option')
if (allOptions[index]) {
allOptions[index].focus()
}
}
},
}" class="w-60 flex flex-col gap-1" x-on:keydown="highlightFirstMatchingOption($event.key)" x-on:keydown.esc.window="isOpen = false, openedWithKeyboard = false">
<div class="relative">
<!-- Trigger Button -->
<button type="button" role="combobox" class="inline-flex w-full items-center justify-between gap-2 whitespace-nowrap border-slate-300 bg-slate-100 px-4 py-2 text-sm font-medium capitalize tracking-wide text-slate-700 transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-700 dark:border-slate-700 dark:bg-slate-800/50 dark:text-slate-300 dark:focus-visible:outline-blue-600 rounded-xl border" aria-haspopup="listbox" aria-controls="industriesList" x-on:click="isOpen = ! isOpen" x-on:keydown.down.prevent="openedWithKeyboard = true" x-on:keydown.enter.prevent="openedWithKeyboard = true" x-on:keydown.space.prevent="openedWithKeyboard = true" x-bind:aria-label="selectedOption ? selectedOption.value : 'Please Select'" x-bind:aria-expanded="isOpen || openedWithKeyboard">
<span class="text-sm font-normal" x-text="selectedOption ? selectedOption.value : '选择创作模式'"></span>
<!-- Chevron -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
</svg>
</button>
<!-- Hidden Input To Grab The Selected Value -->
<input id="ai_mode" name="ai_mode" type="text" x-ref="hiddenTextField" hidden/>
<ul x-cloak x-show="isOpen || openedWithKeyboard" id="industriesList" class="absolute z-10 left-0 top-11 flex max-h-44 w-full flex-col overflow-hidden overflow-y-auto border-slate-300 bg-slate-100 py-1.5 dark:border-slate-700 dark:bg-slate-800 rounded-xl border" role="listbox" aria-label="industries list" x-on:click.outside="isOpen = false, openedWithKeyboard = false" x-on:keydown.down.prevent="$focus.wrap().next()" x-on:keydown.up.prevent="$focus.wrap().previous()" x-transition x-trap="openedWithKeyboard">
<template x-for="(item, index) in options" x-bind:key="item.value">
<li class="combobox-option inline-flex cursor-pointer justify-between gap-6 bg-slate-100 px-4 py-2 text-sm text-slate-700 hover:bg-slate-800/5 hover:text-black focus-visible:bg-slate-800/5 focus-visible:text-black focus-visible:outline-none dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-100/5 dark:hover:text-white dark:focus-visible:bg-slate-100/10 dark:focus-visible:text-white" role="option" x-on:click="setSelectedOption(item)" x-on:keydown.enter="setSelectedOption(item)" x-bind:id="'option-' + index" tabindex="0" >
<!-- Label -->
<span x-bind:class="selectedOption == item ? 'font-bold' : null" x-text="item.label"></span>
<!-- Screen Reader 'Selected' Indicator -->
<span class="sr-only" x-text="selectedOption == item ? 'selected' : null"></span>
<!-- Checkmark -->
<svg x-cloak x-show="selectedOption == item" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2" class="size-4" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
</svg>
</li>
</template>
</ul>
</div>
</div>
<!-- Success Button With Icon -->
<button type="button" x-on:click="do_gen" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded-xl bg-green-600 px-4 py-2 text-xs 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-green-600 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-green-600 dark:text-white dark:focus-visible:outline-green-600">
AI生成
</button>
<!-- Primary Button With Icon -->
<button type="button" x-on:click="do_insert" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded-xl bg-blue-700 px-4 py-2 text-xs font-medium tracking-wide text-slate-100 transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-blue-600 dark:text-slate-100 dark:focus-visible:outline-blue-600">
开头插入
</button>
<!-- Info Button With Icon -->
<button type="button" x-on:click="do_cur_insert" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded-xl bg-sky-600 px-4 py-2 text-xs 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-600 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>
<!-- Info Button With Icon -->
<button type="button" x-on:click="do_replace" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded-xl bg-sky-600 px-4 py-2 text-xs 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-600 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 type="button" x-on:click="do_end_insert" class="cursor-pointer inline-flex justify-center items-center gap-2 whitespace-nowrap rounded-xl bg-indigo-700 px-4 py-2 text-xs font-medium tracking-wide text-slate-100 transition hover:opacity-75 text-center focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-700 active:opacity-100 active:outline-offset-0 disabled:opacity-75 disabled:cursor-not-allowed dark:bg-indigo-600 dark:text-slate-100 dark:focus-visible:outline-indigo-600">
末尾插入
</button>
</div>
<!-- Dialog Body -->
<div id="ai_creator" x-show="!search_list" class="px-4 flex-grow overflow-y-auto min-h-[40vh] min-w-[24rem] md:min-w-[32rem]" x-html="message"> </div>
<div x-show="search_list" class="flex flex-col gap-2 px-4 flex-grow overflow-y-auto min-h-[40vh] min-w-[24rem]">
<template x-for="(item,index) in aItems" key="index">
<label class="flex w-fit min-w-[14rem] cursor-pointer items-center justify-start gap-2 rounded border border-zinc-300 bg-zinc-100 px-4 py-2 font-medium text-neutral-600 has-[:disabled]:opacity-75 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">
<input type="radio" name="radioDefault" :value="index" x-model="search_checked" class="before:content[''] relative h-4 w-4 appearance-none rounded-full border border-zinc-300 bg-zinc-50 before:invisible before:absolute before:left-1/2 before:top-1/2 before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2 before:rounded-full before:bg-white checked:border-sky-700 checked:bg-sky-700 checked:before:visible focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-zinc-500 checked:focus:outline-sky-700 disabled:cursor-not-allowed dark:border-zinc-700 dark:bg-zinc-900 dark:before:bg-white dark:checked:border-sky-600 dark:checked:bg-sky-600 dark:focus:outline-zinc-500 dark:checked:focus:outline-sky-600">
<span class="text-sm" x-text="item.base+':'+item.f_name">Mac</span>
</label>
</template>
</div>
<!-- Dialog Footer -->
<div class="flex flex-col-reverse justify-between gap-2 border-t border-slate-300 bg-slate-100/60 p-2 dark:border-slate-700 dark:bg-slate-900/20 sm:flex-row sm:items-center md:justify-end">
<!-- AI input-->
<div class="relative w-full">
<label for="aiPromt" for="aiPromt" class="sr-only">ai prompt</label>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" aria-hidden="true" class="absolute left-3 top-1/2 size-4 -translate-y-1/2 fill-blue-700 dark:fill-blue-600">
<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>
<input id="aiPromt" x-model="query" x-on:keydown.enter="chat_gen" type="text" class="w-full border-outline bg-slate-100 border border-slate-300 rounded-xl px-2 py-2 pl-10 pr-24 text-sm text-slate-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-700 disabled:cursor-not-allowed disabled:opacity-75 dark:border-slate-700 dark:bg-slate-800/50 dark:text-slate-300 dark:focus-visible:outline-blue-600" name="prompt" placeholder="Ask AI ..." />
<button type="button" x-on:click="chat_gen" class="absolute right-3 top-1/2 -translate-y-1/2 cursor-pointer bg-blue-700 rounded-xl px-2 py-1 text-xs tracking-wide text-slate-100 transition hover:opacity-75 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-700 active:opacity-100 active:outline-offset-0 dark:bg-blue-600 dark:text-slate-100 dark:focus-visible:outline-blue-600">Go</button>
</div>
</div>
</div>
</div>
</template>
<!-- 通知窗口-->
<!-- Success Alert -->
<template x-if="save_fin">
<div class="fixed bottom-4 left-0 right-0 z-30 mx-auto max-w-2xl w-full overflow-hidden rounded border border-green-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-green-700/10 p-4">
<div class="bg-green-700/15 text-green-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="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-2">
<h3 class="text-sm font-semibold text-green-700" x-text="doc_length">保存成功</h3>
<p class="text-xs font-medium sm:text-sm">窗口会在3秒后自动消失你也可以手工关闭</p>
</div>
<button @click="save_fin=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>
</template>
<template x-if="chat_modalIsOpen">
<!-- PPT对话设置窗口 -->
<div x-transition.opacity.duration.200ms x-trap.inert.noscroll="chat_modalIsOpen" x-on:keydown.esc.window="chat_modalIsOpen = ppt_modalIsOpen = poster_modalIsOpen = false" x-on:click.self="chat_modalIsOpen = ppt_modalIsOpen = poster_modalIsOpen = false" class="fixed inset-0 z-30 flex w-full h-100vh items-start justify-end bg-black/20 backdrop-blur-md" role="dialog" aria-modal="true" aria-labelledby="defaultModalTitle">
<!-- Modal Dialog -->
<div x-show="chat_modalIsOpen" 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-100 flex-col gap-4 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 p-4 dark:border-zinc-700 dark:bg-zinc-900/20">
<h3 id="defaultModalTitle" class="font-semibold tracking-wide text-neutral-900 dark:text-zinc-50">生成助手</h3>
<button x-on:click="chat_modalIsOpen = ppt_modalIsOpen = poster_modalIsOpen = 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 -->
<template x-if="ppt_modalIsOpen">
<div id="ppt_ai_dialog" alp-unit="ppt_chat.aps"></div>
</template>
<template x-if="poster_modalIsOpen">
<div id="poster_ai_dialog" alp-unit="poster_chat.aps"></div>
</template>
</div>
</div>
</template>
<template x-if="successModalIsOpen">
<div x-cloak x-show="successModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="successModalIsOpen" x-on:keydown.esc.window="successModalIsOpen = false" x-on:click.self="successModalIsOpen = false" class="fixed inset-0 z-30 flex items-end justify-center bg-black/20 p-4 pb-8 backdrop-blur-md sm:items-center lg:p-8" role="dialog" aria-modal="true" aria-labelledby="successModalTitle">
<!-- Modal Dialog -->
<div x-show="successModalIsOpen" 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 max-w-lg flex-col gap-4 overflow-hidden rounded-radius border border-outline bg-surface text-on-surface dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark">
<!-- Dialog Header -->
<div class="flex items-center justify-between border-b border-outline bg-surface-alt/60 px-4 py-2 dark:border-outline-dark dark:bg-surface-dark/20">
<div class="flex items-center justify-center rounded-full bg-success/20 text-success 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="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" />
</svg>
</div>
<h3 id="successModalTitle" class="mb-2 font-semibold tracking-wide text-on-surface-strong dark:text-on-surface-dark-strong">
<span x-text="share_title"></span>
PPT和海报编辑技巧</h3>
<button x-on:click="successModalIsOpen = 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">
<h3 class="mb-2 font-semibold tracking-wide text-on-surface-strong">标记使用大全</h3>
<p>H1 &nbsp;&nbsp;是PPT和海报的标题(必选)</p>
<p>H3 &nbsp;&nbsp;是PPT和海报的副标题(在第一个H2之前,必选)</p>
<p>H2 &nbsp;&nbsp;是PPT单页主标题或海报的章节主标题(必选)H2在文中会有一横线作为区分</p>
<p>H3 &nbsp;&nbsp;是PPT单页副标题或海报的章节副标题(可选,可以有多个)</p>
<p>H4 &nbsp;&nbsp;是海报的摘要内容,一个海报一般只有一个(可选)</p>
<p>H5 &nbsp;&nbsp;是PPT内容或海报内容一级标题</p>
<p>li &nbsp;&nbsp;是PPT内容或海报内容二级标题可以是有序或无序</p>
<p>p &nbsp;&nbsp;是PPT内容或海报内容三级标题</p>
<p>hr &nbsp;&nbsp;横线表示海报的尾部后续可以添加图片和h5以及p</p>
<p>图片可以添加描述,用做图片的标题显示</p>
</div>
<!-- Dialog Footer -->
<div class="flex items-center justify-center border-outline p-4 dark:border-outline-dark">
<button x-on:click="successModalIsOpen = false" type="button" class="w-full whitespace-nowrap rounded-radius border border-success bg-success px-4 py-2 text-center text-sm font-semibold tracking-wide text-on-success transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-success active:opacity-100 active:outline-offset-0">开始体验</button>
</div>
</div>
</div>
</template>
</div>
</div>
</body>
<script src="wang/wangedit.js"></script>
<script>
const { createEditor, createToolbar,Boot } = window.wangEditor
class MyButtonMenu {
constructor() {
this.title = 'AI' // 自定义菜单标题
// this.iconSvg = '<svg>...</svg>' // 可选
this.tag = 'button'
}
getValue(editor) { // JS 语法
return ''
}
//是否需要激活
isActive(editor) { // JS 语法
return false
}
//是否禁用
isDisabled(editor) { // JS 语法
return false
}
//启用时的动作
exec(editor, value) { // JS 语法
if (this.isDisabled(editor)) return
var text = editor.getSelectionText();
Alpine.store('ai_job').open(text);
//editor.insertText(value) // value 即 this.value(editor) 的返回值
}
}
const menu1Conf = {
key: 'menu-ai', // 定义 menu key :要保证唯一、不重复(重要)
factory() {
return new MyButtonMenu() // 把 `YourMenuClass` 替换为你菜单的 class
},
}
Boot.registerMenu(menu1Conf)
const editorConfig = {
placeholder: '开始输入',
MENU_CONF: {
//上传图片
uploadImage: {
server: '/api/uploadimg',
fieldName: 'file',
base64LimitSize: 2 * 1024,// 2k以下插入 base64
// 单个文件的最大体积限制,默认为 2M
maxFileSize: 50 * 1024 * 1024, // 50M
maxNumberOfFiles: 50, //最多可上传几个文件
},
//上传视频
uploadVideo: {
server: '/api/uploadvideo',
fieldName: 'file',
maxNumberOfFiles: 50, //最多可上传几个文件
// 单个文件的最大体积限制,默认为 10M
maxFileSize: 1000 * 1024 * 1024, // 5M
}
},
onChange(editor) {
const html = editor.getHtml()
//console.log('editor content', html)
// 也可以同步到 <textarea>
},
}
const editor = createEditor({
selector: '#editor-container',
html: '',
config: editorConfig,
mode: 'default', // or 'simple'
})
const toolbarConfig = {}
toolbarConfig.insertKeys = {
index: 0, // 插入的位置,基于当前的 toolbarKeys
keys: ['menu-ai'],
}
const toolbar = createToolbar({
editor,
selector: '#toolbar-container',
config: toolbarConfig,
mode: 'default', // or 'simple'
})
console.info(editor.getConfig().hoverbarKeys);
editor.getConfig().hoverbarKeys.text.menuKeys.unshift("menu-ai");
const url = new URL(window.location.href);
var baike_id = url.searchParams.get('id');
if (baike_id!==undefined){
baike_id=parseInt(baike_id);
}
//可以再外部js调用的一种方式
//A使用Alpine.store('ai_job').open();
document.addEventListener('alpine:init', () => {
Alpine.store('ai_job', {
title:"自动标题",
catalog:"词条",
modalIsOpen: false, //AI创作的窗口
chat_modalIsOpen: false, //ppt和海报对话设置的窗口
ppt_modalIsOpen: false, //ppt对话设置的窗口
poster_modalIsOpen: false, //海报对话设置的窗口
successModalIsOpen: false, //技巧窗口
save_fin: false,
search: "",
search_list: false,
search_checked: "-1",
aItems:[],
progressbar: false, //进度条,显示
currentVal: 20 , //进度条默认值
minVal: 0 ,//进度条最新值
maxVal: 100, //进度条做大值
calcPercentage(min, max, val){return ((val-min)/(max-min))*100},
init(){
//动态加载,AI对话框
this.$watch('ppt_modalIsOpen',value => {
if (value){
this.$nextTick(() => {
var dom = document.getElementById("ppt_ai_dialog")
scan_alp_units(dom);
});
}
});
//动态加载,AI对话框
this.$watch('poster_modalIsOpen',value => {
if (value){
this.$nextTick(() => {
var dom = document.getElementById("poster_ai_dialog")
scan_alp_units(dom);
});
}
});
},//初始化函数
tips: "<span class='bg-green-600 text-white px-4 py-1 text-xs font-medium'>提示:</span>"
+"&nbsp;&nbsp;我是人工智能助手,我可以帮你完成文档创作。请先选择创作的模式然后点击上方的"
+"<span class='bg-green-600 rounded-xl text-white px-4 py-1 text-xs font-medium opacity-50'>AI生成</span>按钮,就会自动生成内容,满意的话可以选择插入或替换文本,不满意的话可以再次点击按钮重新生成。<br><br>"
+"AI续写 根据上文的内容自动续写后续的内容,可以不选中内容<br>"
+"AI摘要 根据上文的内容自动编写一个摘要,可以不选中内容<br>"
+"AI大纲 根据选中的文字一般是标题来进行思维脑图式的创作<br>"
+"AI丰富 对选中的文字内容进行扩写,使其内容变长<br>"
+"AI优化 对选中的文字内容进行缩写,使其更加精简<br>"
+"拼写检查: 对选中的文字的内容进行错别字等检查和修复<br>"
+"智能翻译: 中文翻译成引文或英文翻译成中文<br>"
+"<br>也可以用知识对话的方式来生成所需的内容<br>"
,
message: "",
context: "",
catalogs: "",
query: "",
doc_length:"",
x: 0,
y: 0,
dragging: false,
dragStart(e) {
this.dragging = true;
this.startX = e.clientX - this.x;
this.startY = e.clientY - this.y;
},
drag(e) {
if (!this.dragging) return;
this.x = e.clientX - this.startX;
this.y = e.clientY - this.startY;
},
open(text){
this.modalIsOpen=true;
this.context = text;
this.message = "<span class='bg-yellow-300 text-white'>"+text+"</span><br><br>"+this.tips;
const div = document.getElementById("ai_creator");
div.scrollTop = 0;
},
up_message(msg){
this.message=msg;
},
do_insert(){
editor.focus();
let html = editor.getHtml();
editor.clear();
editor.dangerouslyInsertHtml(this.pre_message())
editor.dangerouslyInsertHtml(html);
const div = document.querySelector(".w-e-scroll")
div.scrollTop = 0;
},
do_cur_insert(){
//editor.blur()
editor.focus();
// if (editor.selection){
// console.info("选中")
// editor.deselect()
// }else{
// console.info("未选")
// }
editor.dangerouslyInsertHtml(this.context+this.pre_message())
},
do_replace(){
editor.focus()
editor.deleteFragment();
editor.dangerouslyInsertHtml(this.pre_message())
},
do_end_insert(){
editor.focus();
let html = editor.getHtml();
editor.clear();
editor.dangerouslyInsertHtml(html);
editor.dangerouslyInsertHtml(this.pre_message())
const div = document.querySelector(".w-e-scroll")
div.scrollTop = div.scrollHeight;;
},
pre_message(){ //纯的message,没有思考过程
let end = this.message.lastIndexOf('padding:5px;">');
var rsp = this.message.slice(end+'padding:5px;">'.length,-6);
return rsp;
},
//初始化
init2(){
this.baike_id= baike_id;
if (baike_id !==0){
axios.get('/api/baike/'+baike_id).then(response => {
this.title= response.data.title;
this.catalog=response.data.catalog;
editor.setHtml(response.data.html);
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}
//分类
axios.get('/api/catalogs').then(response => {
//console.log('Data:', response.data);
this.catalogs = response.data.data;
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
//保存编辑信息
do_save(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
trans: false,
html: editor.getHtml()
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike', newItem)
.then(response =>{
//alert(response.data.msg)
this.doc_length = `保存成功,大约${editor.getText().length}`;
this.save_fin = true;
this.baike_id = response.data.id
setTimeout(() => {
this.save_fin = false;
}, 3000); // 3000 毫秒 = 3 秒
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
//保存编辑信息为text格式
do_save_text(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
trans: false,
html: editor.getText()
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike', newItem)
.then(response =>{
//alert(response.data.msg)
this.save_fin = true;
this.doc_length = `保存成功,大约${editor.getText().length}`;
this.baike_id = response.data.id
setTimeout(() => {
this.save_fin = false;
}, 3000); // 3000 毫秒 = 3 秒
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
//生成word文档
gen_word(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
html: editor.getHtml()
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike_gen_word', newItem)
.then(response =>{
window.open(`/api/fsd/${response.data.filename}`);
})
.catch(error => {
alert(error.response.data.detail);
});
},
//生成pdf文档
gen_pdf(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
html: editor.getHtml()
};
// 使用 axios 发送 POST 请求
axios.post('/api/baike_gen_pdf', newItem)
.then(response =>{
window.open(`/api/fsd/${response.data.filename}`);
})
.catch(error => {
alert(error.response.data.detail);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
//生成PPT文档
gen_ppt(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
html: editor.getHtml()
};
this.progressbar = true;
this.currentVal =10;
setInterval(() => {
this.currentVal +=10;
}, 1000); // 1秒
// 使用 axios 发送 POST 请求
axios.post('/api/baike_gen_ppt', newItem)
.then(response =>{
this.progressbar = false;
window.open(`/api/fsd/${response.data.filename}`);
})
.catch(error => {
this.progressbar = false;
alert(error.response.data.detail);
});
},
//打开ppt设置的对话框
gen_ppt2(event){
this.chat_modalIsOpen = true;
this.ppt_modalIsOpen = true;
event.stopPropagation(); // 阻止事件冒泡
return false;
},
//生成海报
gen_poster(){
// 数据对象,代表要发送的数据
const newItem = {
id: this.baike_id,
title: this.title,
catalog: this.catalog,
html: editor.getHtml()
};
this.progressbar = true;
this.currentVal =10;
setInterval(() => {
this.currentVal +=10;
}, 1000); // 1秒
// 使用 axios 发送 POST 请求
axios.post('/api/baike_gen_poster', newItem)
.then(response =>{
this.progressbar = false;
window.open(`/api/fsd/${response.data.filename}`);
})
.catch(error => {
this.progressbar = false;
alert(error.response.data.detail);
});
},
gen_poster2(event){
this.chat_modalIsOpen = true;
this.poster_modalIsOpen = true;
event.stopPropagation(); // 阻止事件冒泡
return false;
},
do_gen(){
this.message="";
this.search_list = false;
const input_ai_mode = document.getElementById("ai_mode");
if (input_ai_mode.value==""){
alert("请选择创作模式");
return;
}
if (input_ai_mode.value=="指令模式"){
alert("请在下方输入框输入指令,点击GO即可完成");
return;
}
if (input_ai_mode.value=="AI续写" && this.context==""){
this.context=editor.getText();
}
if (input_ai_mode.value=="AI摘要" && this.context==""){
this.context=editor.getText();
}
// 数据对象,代表要发送的数据
const newItem = {
question: this.context,
ai_mode: input_ai_mode.value,
};
// 使用 axios 发送 POST 请求
axios.post('/api/ai_create', newItem)
.then(response =>{
rsp = response.data;
// 创建一个EventSource实例连接到服务器发送的事件流
const eventSource = new EventSource('/api/ai_create/'+rsp.chat_id);
// 监听消息事件
eventSource.onmessage = function(event) {
// 将接收到的数据显示在网页上
const message = JSON.parse(event.data);
var gen_rsp ="";
if (message.rsp.indexOf("<think>")==0){
var end = message.rsp.indexOf("</think>");
if (end==-1){ //思考还未结束
var think_mk = marked.parse(message.rsp.slice(7));
gen_rsp = think_mk;
}else{
var think_mk = marked.parse(message.rsp.slice(7,end));
var result= marked.parse(message.rsp.slice(end+8));
var think_all=`${think_mk} <div style="color: white; background-color: rgb(29 78 216 / 0.9); border-radius: 5px; margin: 5px; padding:5px;">${result}</div>`;
gen_rsp= think_all;
}
}else{
gen_rsp =marked.parse(message.rsp);
}
Alpine.store('ai_job').up_message(gen_rsp);
const div = document.getElementById("ai_creator");
div.scrollTop = div.scrollHeight;
};
// 监听错误事件
eventSource.onerror = function(error) {
console.error("EventSource failed:", error);
eventSource.close(); // 关闭连接
};
})
.catch(error => {
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
chat_gen(){
this.search_list = false;
this.message="";
const input_ai_mode = document.getElementById("ai_mode");
var mode="KG"; //知识库问答
if (input_ai_mode.value=="指令模式"){
mode="FA"; //大模型回答
}
if (this.search_checked=="-1" || mode=="FA"){
// 数据对象,代表要发送的数据
const newItem = {
question: this.context+"\n"+this.query,
ai_mode: mode,
};
// 使用 axios 发送 POST 请求
axios.post('/api/chat_search', newItem)
.then(response =>{
this.query="";
rsp = response.data;
// this.Items[this.Items.length-1].chat_id=rsp.chat_id;
// this.Items[this.Items.length-1].rsp=`搜索到${rsp.count}篇文档[${rsp.meta}],正在整理中...`;
// this.Items[this.Items.length-1].rsp_show=true;
update_chat(rsp.chat_id);
})
.catch(error => {
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}else
{ //单个文档回答
let doc_index=parseInt(this.search_checked);
let doc= this.aItems[doc_index];
//单个文档对话
// 数据对象,代表要发送的数据
const newItem = {
question: this.query,
file: doc.f_name,
base: doc.base,
path: doc.path,
};
// 使用 axios 发送 POST 请求
axios.post('/api/chat_one_doc', newItem)
.then(response =>{
this.query="";
rsp = response.data;
update_chat(rsp.chat_id);
})
.catch(error => {
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}
},
fetchSomething() {//查询文档
this.search_list = true;
if (this.search==""){
return;
}
axios.get('/api/kg_doc?demo='+this.search).then(response => {
//console.log('Data:', response.data);
this.aItems = response.data.data;
this.search_checked = -1;
this.count=response.data.count;
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
},
})
})
function update_chat(chat_id){
// 创建一个EventSource实例连接到服务器发送的事件流
const eventSource = new EventSource('/api/chat/'+chat_id);
// 监听消息事件
eventSource.onmessage = function(event) {
// 将接收到的数据显示在网页上
const message = JSON.parse(event.data);
var gen_rsp ="";
if (message.rsp.indexOf("<think>")==0){
var end = message.rsp.indexOf("</think>");
if (end==-1){ //思考还未结束
var think_mk = marked.parse(message.rsp.slice(7));
gen_rsp = think_mk;
}else{
var think_mk = marked.parse(message.rsp.slice(7,end));
var result= marked.parse(message.rsp.slice(end+8));
var think_all=`${think_mk} <div style="color: white; background-color: rgb(29 78 216 / 0.9); border-radius: 5px; margin: 5px; padding:5px;">${result}</div>`;
gen_rsp= think_all;
}
}else{
gen_rsp =marked.parse(message.rsp);
}
Alpine.store('ai_job').up_message(gen_rsp);
const div = document.getElementById("ai_creator");
div.scrollTop = div.scrollHeight;
};
// 监听错误事件
eventSource.onerror = function(error) {
console.error("EventSource failed:", error);
eventSource.close(); // 关闭连接
};
}
function auto_save(){
var catalog = document.getElementById('catalog').value;
if ( catalog.startsWith("大模型/") )
var button = document.getElementById('save_text');
else{
var button = document.getElementById('save');
}
// 触发点击事件
button.click();
}
//开启30 秒后,自动保存
let timerId = setTimeout(() => {
//定时60秒保存
setInterval(auto_save,60000);
}, 60000);
</script>
</html>