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

313 lines
16 KiB
HTML

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI知识共享平台-让知识流动起来</title>
<link rel="icon" href="images/logo2.png" sizes="16x16" type="image/png">
<!--<script src="https://cdn.tailwindcss.com"></script>-->
<link rel="stylesheet" href="highlight.min.css">
<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>
<script src="js/highlight.min.js"></script>
<script src="js/chart.449.min.js"></script>
<script src="js/draw_chart.js"></script>
<script>
// 配置marked
marked.setOptions({
highlight: function(code, lang) {
return hljs.highlightAuto(code).value;
},
breaks: true
});
function copyToClipboard(text) {
// 检查是否支持 clipboard API
if (navigator.clipboard) {
// 复制文本到剪贴板
navigator.clipboard.writeText(text)
.then(() => {
console.log('内容已复制到剪贴板');
})
.catch(err => {
console.error('无法复制文本: ', err);
});
} else {
fallbackCopyTextToClipboard(text);
}
}
function fallbackCopyTextToClipboard(text) {
// 创建一个临时的 textarea 元素
var textArea = document.createElement("textarea");
textArea.value = text;
// 隐藏元素避免页面布局变化
textArea.style.position = 'fixed';
textArea.style.top = '0';
textArea.style.left = '0';
textArea.style.width = '2em';
textArea.style.height = '2em';
textArea.style.padding = '0';
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
textArea.style.background = 'transparent';
document.body.appendChild(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? '成功复制到剪贴板' : '未能复制文本';
console.log(msg);
} catch (err) {
console.error('无法执行命令: ', err);
}
document.body.removeChild(textArea);
}
//格式化输出文件大小
function formatBytes(bytes, decimals = 1) {
if (bytes === -1) return '';
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
</script>
<style>
/* WebKit 浏览器的滚动条 */
::-webkit-scrollbar {
width: 4px; /* 滚动条宽度 */
height: 4px;
}
::-webkit-scrollbar-track {
background: #f1f1f1; /* 轨道背景色 */
}
::-webkit-scrollbar-thumb {
background: #888; /* 滚动条颜色 */
border-radius: 4px; /* 圆角 */
}
::-webkit-scrollbar-thumb:hover {
background: #555; /* 滚动条悬停时的颜色 */
}
#logo {
width: 200px;
height: 50px;
}
hr {
border: none; /* 移除默认边框 */
height: 1px; /* 设置线条的高度 */
background-color: #ddd; /* 线条的颜色 */
margin: 20px 0; /* 上下外边距 */
}
/* 表格基础样式 */
table {
width: 100%; /* 让表格占据其容器的全宽 */
border-collapse: collapse; /* 合并边框 */
background-color: white; /* 灰*/
}
/* 表头样式 */
th {
background-color: #808080; /* 灰*/
color: white; /* 白色文字 */
font-weight: bold; /* 加粗字体 */
text-align: left; /* 左对齐文本 */
padding: 8px; /* 内边距 */
border: 1px solid #ddd; /* 边框 */
}
/* 标准单元格样式 */
td {
border: 1px solid #ddd; /* 边框 */
padding: 8px; /* 内边距 */
text-align: left; /* 左对齐文本 */
color: #828282; /* 灰色文字 */
}
/* 隔行变色 */
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 鼠标悬停时高亮行 */
tr:hover {
background-color: #ddd;
}
</style>
</head>
<body>
<div x-data="$store.nav" class="w-full h-screen overflow-hidden">
<div class="flex justify-between border-b-2 text-sky-700 dark:border-zinc-700">
<div id="slogan" class="font-bold py-2 "><a target="_blank" href="/">AI知识共享平台-让知识流动起来</a>
</div>
<div @keydown.right.prevent="$focus.wrap().next()" @keydown.left.prevent="$focus.wrap().previous()" class="flex justify-end gap-2 overflow-x-auto border-zinc-300 dark:border-zinc-700" role="tablist" aria-label="tab options">
<button @click="selectedTab = 'ground'" :aria-selected="selectedTab === 'ground'" :tabindex="selectedTab === 'ground' ? '0' : '-1'" :class="selectedTab === 'ground' ? 'font-bold text-sky-700 border-b-2 border-sky-700 dark:border-sky-600 dark:text-sky-600' : 'text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:border-b-zinc-500 hover:text-neutral-900'" class="flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelComments" >
<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="M10.362 1.093a.75.75 0 0 0-.724 0L2.523 5.018 10 9.143l7.477-4.125-7.115-3.925ZM18 6.443l-7.25 4v8.25l6.862-3.786A.75.75 0 0 0 18 14.25V6.443ZM9.25 18.693v-8.25l-7.25-4v7.807a.75.75 0 0 0 .388.657l6.862 3.786Z"/>
</svg>
&nbsp;&nbsp;&nbsp;
</button>
<button @click="selectedTab = 'comments'" :aria-selected="selectedTab === 'comments'" :tabindex="selectedTab === 'comments' ? '0' : '-1'" :class="selectedTab === 'comments' ? 'font-bold text-sky-700 border-b-2 border-sky-700 dark:border-sky-600 dark:text-sky-600' : 'text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:border-b-zinc-500 hover:text-neutral-900'" class="flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelComments" >
<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>
知识对话
</button>
<button @click="selectedTab = 'likes'" :aria-selected="selectedTab === 'likes'" :tabindex="selectedTab === 'likes' ? '0' : '-1'" :class="selectedTab === 'likes' ? 'font-bold text-sky-700 border-b-2 border-sky-700 dark:border-sky-600 dark:text-sky-600' : 'text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:border-b-zinc-500 hover:text-neutral-900'" class="flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelLikes" >
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="size-5">
<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>
知识创作
<!--
<span x-text="baike_count" :class="selectedTab === 'likes' ? 'border-sky-700 bg-sky-700/10 dark:bg-sky-600 dark:border-sky-600 dark:text-white' : 'border-zinc-300 dark:border-zinc-700 bg-zinc-100 dark:bg-zinc-800'" class="text-xs border font-medium px-1 rounded-full">3124</span>
-->
</button>
<button @click="selectedTab = 'groups'" :aria-selected="selectedTab === 'groups'" :tabindex="selectedTab === 'groups' ? '0' : '-1'" :class="selectedTab === 'groups' ? 'font-bold text-sky-700 border-b-2 border-sky-700 dark:border-sky-600 dark:text-sky-600' : 'text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:border-b-zinc-500 hover:text-neutral-900'" class="flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelGroups" >
<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>
知识管理
</button>
<template x-if="is_admin">
<button @click="selectedTab = 'saved'" :aria-selected="selectedTab === 'saved'" :tabindex="selectedTab === 'saved' ? '0' : '-1'" :class="selectedTab === 'saved' ? 'font-bold text-sky-700 border-b-2 border-sky-700 dark:border-sky-600 dark:text-sky-600' : 'text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:border-b-zinc-500 hover:text-neutral-900'" class="flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelSaved">
<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>
系统管理
</button>
</template>
<button @click="window.location.href='/api/logout'" class="text-neutral-600 font-medium dark:text-zinc-200 dark:hover:border-b-zinc-500 dark:hover:text-zinc-50 hover:border-b-2 hover:bg-blue-700/1 hover:border-b-zinc-500 hover:text-neutral-900 flex h-min items-center gap-2 px-4 py-2 pl-2 text-sm" type="button" role="tab" aria-controls="tabpanelSaved" title="退出系统">
[<span x-text="username" alt="退出系统"></span>]
</button>
<!--
<div class="flex justify-between small py-2 text-sm">[<span x-text="username" @click="window.location.href='/api/logout'" alt="退出系统"></span>]</div>
-->
</div>
</div>
<!--导航下的页面内容 -->
<div class="px-2 text-neutral-600 dark:text-zinc-200">
<div x-show="selectedTab === 'ground'" id="tabpanelComments" role="tabpanel" aria-label="ground">
<div alp-unit="ground.aps"></div>
</div>
<div x-show="selectedTab === 'groups'" id="tabpanelGroups" role="tabpanel" aria-label="groups">
<div alp-unit="project.aps"></div>
</div>
<div x-show="selectedTab === 'likes'" id="tabpanelLikes" role="tabpanel" aria-label="likes">
<div alp-unit="baike.html"></div>
</div>
<div x-show="selectedTab === 'comments'" id="tabpanelComments" role="tabpanel" aria-label="comments">
<div alp-unit="chat.aps"></div>
</div>
<div x-show="selectedTab === 'saved' && is_admin" id="tabpanelSaved" role="tabpanel" aria-label="saved"><b>
<div alp-unit="system.aps"></div>
</div>
</div>
</div>
</body>
<script>
const url = new URL(window.location.href);
var cur_tab = url.searchParams.get('tab');
if (cur_tab==undefined){
//默认智能体
cur_tab='ground';
}
document.addEventListener('alpine:init', () => {
console.log("alpine:init");
//为了实现文档到对话,对话到百科的跳转,建立全局对象,保存对话历史等信息
Alpine.store('nav', {
username: "",
selectedTab: cur_tab, //当前tab
ai_file: {},
ai_tips:"你好,我可以帮你检索知识库并回答你的问题。请问我有什么可以帮助你的?",
Items:[], //对话过程所有信息
qItems:[], //对话问题的列表,用于多轮对话
is_ground: true, //true是广场, false是对话窗口
is_admin:false,
logo:"images/logo2.jpg",
selected_baike_catalog:"", //选中的百科分类
push_item(item){
this.Items.push(item);
},
push_qitem(item){
this.qItems.push(item);
},
update_last_item(chat_id,title,ctx){
var last = this.Items[this.Items.length-1];
last.chat_id=chat_id;
last.rsp=title;
last.rsp_show=true;
last.ctx=ctx;
},
update_last_qitem(answer){
//更新最后一个问题的答案
var last = this.qItems[this.qItems.length-1];
last.rsp=answer;
},
load_data(){
axios.get('/api/is_admin').then(response => {
this.is_admin = response.data.is_admin;
});
},
init_cfg(){
axios.get('/api/login_cfg').then(response => {
var cfg = response.data;
//
document.getElementById("slogan").innerHTML=cfg.slogan;
document.title = cfg.slogan;
//logo 设置
if (cfg.logo!=""){
this.logo="/api/img/"+cfg.logo;
}
//当前用户
this.username=cfg.username;
});
}
});
// 初始化时加载用户数据
Alpine.store('nav').load_data();
// 初始化时加载用户数据
Alpine.store('nav').init_cfg();
});
</script>
</html>