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

220 lines
19 KiB
Plaintext
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.

<div x-data="{ selectedTab: 'setting' }" class="relative flex w-full flex-col md:flex-row h-[92vh]">
<nav x-cloak class="fixed left-0 z-20 flex h-svh w-60 shrink-0 flex-col border-r border-slate-300 bg-slate-100 p-4 transition-transform duration-300 md:w-64 md:translate-x-0 md:relative dark:border-slate-700 dark:bg-slate-800" aria-label="sidebar navigation">
<!-- sidebar links -->
<div class="flex flex-col gap-2 overflow-y-auto pb-6">
<a href="#" @click="selectedTab = 'setting'" :class="selectedTab === 'setting' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<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>
<span>大模型管理</span>
</a>
<!--
<a href="#" @click="selectedTab = 'source'" :class="selectedTab === 'source' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5 shrink-0" aria-hidden="true">
<path d="M15.5 2A1.5 1.5 0 0 0 14 3.5v13a1.5 1.5 0 0 0 1.5 1.5h1a1.5 1.5 0 0 0 1.5-1.5v-13A1.5 1.5 0 0 0 16.5 2h-1ZM9.5 6A1.5 1.5 0 0 0 8 7.5v9A1.5 1.5 0 0 0 9.5 18h1a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 10.5 6h-1ZM3.5 10A1.5 1.5 0 0 0 2 11.5v5A1.5 1.5 0 0 0 3.5 18h1A1.5 1.5 0 0 0 6 16.5v-5A1.5 1.5 0 0 0 4.5 10h-1Z"/>
</svg>
<span>知识库管理</span>
</a>
-->
<a href="#" @click="selectedTab = 'user'" :class="selectedTab === 'user' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-5">
<path d="M10 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 8a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM1.49 15.326a.78.78 0 0 1-.358-.442 3 3 0 0 1 4.308-3.516 6.484 6.484 0 0 0-1.905 3.959c-.023.222-.014.442.025.654a4.97 4.97 0 0 1-2.07-.655ZM16.44 15.98a4.97 4.97 0 0 0 2.07-.654.78.78 0 0 0 .357-.442 3 3 0 0 0-4.308-3.517 6.484 6.484 0 0 1 1.907 3.96 2.32 2.32 0 0 1-.026.654ZM18 8a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM5.304 16.19a.844.844 0 0 1-.277-.71 5 5 0 0 1 9.947 0 .843.843 0 0 1-.277.71A6.975 6.975 0 0 1 10 18a6.974 6.974 0 0 1-4.696-1.81Z" />
</svg>
<span>用户管理</span>
</a>
<a href="#" @click="selectedTab = 'login'" :class="selectedTab === 'login' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-5">
<path d="m9.653 16.915-.005-.003-.019-.01a20.759 20.759 0 0 1-1.162-.682 22.045 22.045 0 0 1-2.582-1.9C4.045 12.733 2 10.352 2 7.5a4.5 4.5 0 0 1 8-2.828A4.5 4.5 0 0 1 18 7.5c0 2.852-2.044 5.233-3.885 6.82a22.049 22.049 0 0 1-3.744 2.582l-.019.01-.005.003h-.002a.739.739 0 0 1-.69.001l-.002-.001Z" />
</svg>
<span>日志管理</span>
</a>
<a href="#" @click="selectedTab = 'chat_history'" :class="selectedTab === 'chat_history' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="size-5">
<path d="M3.505 2.365A41.369 41.369 0 0 1 9 2c1.863 0 3.697.124 5.495.365 1.247.167 2.18 1.108 2.435 2.268a4.45 4.45 0 0 0-.577-.069 43.141 43.141 0 0 0-4.706 0C9.229 4.696 7.5 6.727 7.5 8.998v2.24c0 1.413.67 2.735 1.76 3.562l-2.98 2.98A.75.75 0 0 1 5 17.25v-3.443c-.501-.048-1-.106-1.495-.172C2.033 13.438 1 12.162 1 10.72V5.28c0-1.441 1.033-2.717 2.505-2.914Z" />
<path d="M14 6c-.762 0-1.52.02-2.271.062C10.157 6.148 9 7.472 9 8.998v2.24c0 1.519 1.147 2.839 2.71 2.935.214.013.428.024.642.034.2.009.385.09.518.224l2.35 2.35a.75.75 0 0 0 1.28-.531v-2.07c1.453-.195 2.5-1.463 2.5-2.915V8.998c0-1.526-1.157-2.85-2.729-2.936A41.645 41.645 0 0 0 14 6Z" />
</svg>
<span>历史对话</span>
</a>
<a href="#" @click="selectedTab = 'gcfg'" :class="selectedTab === 'gcfg' ? 'bg-blue-700/30' : ''" class="flex items-center rounded-xl gap-2 px-2 py-1.5 text-sm font-medium text-slate-700 underline-offset-2 hover:bg-blue-700/5 hover:text-black focus-visible:underline focus:outline-none dark:text-slate-300 dark:hover:bg-blue-600/5 dark:hover:text-white">
<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="M7.84 1.804A1 1 0 0 1 8.82 1h2.36a1 1 0 0 1 .98.804l.331 1.652a6.993 6.993 0 0 1 1.929 1.115l1.598-.54a1 1 0 0 1 1.186.447l1.18 2.044a1 1 0 0 1-.205 1.251l-1.267 1.113a7.047 7.047 0 0 1 0 2.228l1.267 1.113a1 1 0 0 1 .206 1.25l-1.18 2.045a1 1 0 0 1-1.187.447l-1.598-.54a6.993 6.993 0 0 1-1.929 1.115l-.33 1.652a1 1 0 0 1-.98.804H8.82a1 1 0 0 1-.98-.804l-.331-1.652a6.993 6.993 0 0 1-1.929-1.115l-1.598.54a1 1 0 0 1-1.186-.447l-1.18-2.044a1 1 0 0 1 .205-1.251l1.267-1.114a7.05 7.05 0 0 1 0-2.227L1.821 7.773a1 1 0 0 1-.206-1.25l1.18-2.045a1 1 0 0 1 1.187-.447l1.598.54A6.992 6.992 0 0 1 7.51 3.456l.33-1.652ZM10 13a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" clip-rule="evenodd"/>
</svg>
<span>系统参数</span>
</a>
</div>
</nav>
<!-- main content -->
<div id="main-content" class="h-[92vh] w-full overflow-y-auto p-4 bg-white dark:bg-slate-900">
<div x-show="selectedTab === 'gcfg'" class="w-full h-full">
<div alp-unit="gcfg.html"></div>
</div>
<div x-show="selectedTab === 'user'" class="w-full h-full">
<div alp-unit="user.html"></div>
</div>
<div x-show="selectedTab === 'login'" class="w-full h-full">
<div alp-unit="logs.html"></div>
</div>
<div x-show="selectedTab === 'chat_history'" class="w-full h-full">
<div alp-unit="chat_history.html"></div>
</div>
<template x-if="selectedTab === 'setting'">
<div class="w-full h-full">
<!-- 大模型设置 -->
<div
x-data="{
tabSelected: '',
save_fin: false,
llm_cfg:[],
chat_modalIsOpen:false,
tabButtonClicked(tab,tabButton){
this.tabSelected = tab
this.tabRepositionMarker(tabButton);
},
tabRepositionMarker(tabButton){
this.$refs.tabMarker.style.width=tabButton.offsetWidth + 'px';
this.$refs.tabMarker.style.height=tabButton.offsetHeight + 'px';
this.$refs.tabMarker.style.left=tabButton.offsetLeft + 'px';
},
init(){
axios.get('/api/llm').then(response => {
this.tabSelected = response.data.selected;
this.llm_cfg = response.data.llm_cfg;
$nextTick(() => {
this.tabRepositionMarker(document.getElementById(this.tabSelected))
})
}).catch(error => {
console.error('Error fetching data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
//动态加载,AI对话框
this.$watch('chat_modalIsOpen',value => {
if (value){
this.$nextTick(() => {
var dom = document.getElementById('chat_ai_dialog')
scan_alp_units(dom);
});
}
});
},
save(){
const newItem = {
selected: this.tabSelected,
llm_cfg: this.llm_cfg,
};
// 使用 axios 发送 POST 请求
axios.post('/api/llm', newItem)
.then(response =>{
this.save_fin=true;
console.info(response.data.code);
})
.catch(error => {
alert(error);
console.error('Error post data:', error);
throw error; // 重新抛出错误以便调用者可以处理
});
}
}"
class="mx-auto relative w-full max-w-3xl">
<div class="relative inline-grid items-center justify-center w-full h-10 grid-cols-9 p-1 text-gray-500 bg-gray-100 rounded-lg select-none">
<template x-for="(llm, index) in llm_cfg" :key="index">
<button :id="llm.id" @click="tabButtonClicked(llm.id,$el)" x-text="llm.tab" type="button" class="relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap">本地大模型</button>
</template>
<div x-ref="tabMarker" class="absolute left-0 z-10 w-1/2 h-full duration-300 ease-out" x-cloak><div class="w-full h-full bg-white rounded-md shadow-sm"></div></div>
</div>
<div class="relative w-full mt-2 content">
<template x-for="(llm, index) in llm_cfg" :key="index">
<div x-show="tabSelected==llm.id" class="relative">
<!-- Tab Content 2 - Replace with your content -->
<div class="border rounded-lg shadow-sm bg-card text-neutral-900">
<div class="flex flex-col space-y-1.5 p-6">
<h3 x-text="llm.title" class="text-lg font-semibold leading-none tracking-tight">阿里通义千问大模型</h3>
<p x-text="llm.desc" class="text-sm text-neutral-500">阿里云厂家提供的大模型API,需要付费使用。支持兼容OpenAI的接口形式,可以选择qwen-max,qwen-72b等</p>
</div>
<div class="p-6 pt-0 space-y-2">
<div class="space-y-1"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="password">Server地址</label>
<input type="text" x-model="llm.url" value="https://dashscope.aliyuncs.com/compatible-mode/v1" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50" /></div>
<div class="space-y-1"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="password">模型名称</label>
<input type="text" x-model="llm.name" value="qwen-max" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50" /></div>
<div class="space-y-1"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="password_new">Api_key</label>
<input type="text" x-model="llm.api_key" placeholder="你的api_key" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50" /></div>
</div>
</div>
<!-- End Tab Content 2 -->
</div>
</template>
<div class="flex items-center p-6 pt-4">
<button type="button" @click="save" class="mx-auto 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 type="button" @click="chat_modalIsOpen=true" class="mx-auto 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>
</div>
</div>
<template x-if="chat_modalIsOpen">
<!-- 大模型对话测试窗口 -->
<div x-transition.opacity.duration.200ms x-trap.inert.noscroll="chat_modalIsOpen" x-on:keydown.esc.window="chat_modalIsOpen = false" x-on:click.self="chat_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 = 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 id="chat_ai_dialog" alp-unit="llm_chat.aps"></div>
</div>
</div>
</template>
<!-- 通知窗口-->
<!-- Success Alert -->
<div x-show="save_fin" class="fixed top-10 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">保存成功</h3>
<p class="text-xs font-medium sm:text-sm">大模型配置完成后需要重新启动web服务才能生效</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>
</div>
</div>
</template>
</div>
</div>