feat: 添加系统信息配置功能
- 在 API 路由中新增获取和重新加载系统信息配置的接口。 - 实现信息配置的加载逻辑,并提供默认配置。 - 更新前端以支持动态加载和展示信息配置。 - 修改 Dockerfile,移除代理设置。
This commit is contained in:
parent
2760efcbb7
commit
4ecf9a8cd6
@ -35,8 +35,7 @@ COPY ../src /app/src
|
||||
COPY ../server /app/server
|
||||
|
||||
# 关闭代理设置
|
||||
ENV http_proxy="" \
|
||||
https_proxy=""
|
||||
RUN unset http_proxy https_proxy
|
||||
|
||||
# 同步项目
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
|
||||
@ -1,13 +1,63 @@
|
||||
from fastapi import Request, Body, Depends
|
||||
import os
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from fastapi import Request, Body, Depends, HTTPException
|
||||
from fastapi import APIRouter
|
||||
|
||||
from src import config, retriever, knowledge_base, graph_base
|
||||
from server.utils.auth_middleware import get_admin_user, get_superadmin_user
|
||||
from server.models.user_model import User
|
||||
from src.utils.logging_config import logger
|
||||
|
||||
|
||||
base = APIRouter()
|
||||
|
||||
def load_info_config():
|
||||
"""加载信息配置文件"""
|
||||
try:
|
||||
# 配置文件路径
|
||||
config_path = Path("src/static/info.local.yaml")
|
||||
|
||||
# 检查文件是否存在
|
||||
if not config_path.exists():
|
||||
logger.warning(f"配置文件 {config_path} 不存在,使用默认配置")
|
||||
return get_default_info_config()
|
||||
|
||||
# 读取配置文件
|
||||
with open(config_path, 'r', encoding='utf-8') as file:
|
||||
config = yaml.safe_load(file)
|
||||
|
||||
# logger.info(f"成功加载信息配置文件: {config_path}")
|
||||
return config
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载信息配置文件失败: {e}")
|
||||
return get_default_info_config()
|
||||
|
||||
def get_default_info_config():
|
||||
"""获取默认信息配置"""
|
||||
return {
|
||||
"organization": {
|
||||
"name": "江南大学",
|
||||
"short_name": "语析",
|
||||
"logo": "/favicon.svg",
|
||||
"avatar": "/avatar.jpg"
|
||||
},
|
||||
"branding": {
|
||||
"title": "Yuxi-Know",
|
||||
"subtitle": "大模型驱动的知识库管理工具",
|
||||
"description": "结合知识库与知识图谱,提供更准确、更全面的回答"
|
||||
},
|
||||
"features": [
|
||||
"📚 灵活知识库",
|
||||
"🕸️ 知识图谱集成",
|
||||
"🤖 多模型支持"
|
||||
],
|
||||
"footer": {
|
||||
"copyright": "© 江南大学 2025 [WIP] v0.12.138"
|
||||
}
|
||||
}
|
||||
|
||||
@base.get("/")
|
||||
async def route_index():
|
||||
return {"message": "You Got It!"}
|
||||
@ -58,4 +108,32 @@ def get_log(current_user: User = Depends(get_admin_user)):
|
||||
log = ''.join(last_lines)
|
||||
return {"log": log, "message": "success", "log_file": LOG_FILE}
|
||||
|
||||
@base.get("/info")
|
||||
async def get_info_config():
|
||||
"""获取系统信息配置(公开接口,无需认证)"""
|
||||
try:
|
||||
config = load_info_config()
|
||||
return {
|
||||
"success": True,
|
||||
"data": config
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"获取信息配置失败: {e}")
|
||||
raise HTTPException(status_code=500, detail="获取信息配置失败")
|
||||
|
||||
@base.get("/info/reload")
|
||||
async def reload_info_config():
|
||||
"""重新加载信息配置(管理员接口)"""
|
||||
# 注:这里暂时不添加权限验证,后续可以根据需要添加
|
||||
try:
|
||||
config = load_info_config()
|
||||
return {
|
||||
"success": True,
|
||||
"message": "配置重新加载成功",
|
||||
"data": config
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"重新加载信息配置失败: {e}")
|
||||
raise HTTPException(status_code=500, detail="重新加载信息配置失败")
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ PUBLIC_PATHS = [
|
||||
r"^/api/auth/initialize$", # 初始化系统
|
||||
r"^/api$", # Health Check
|
||||
r"^/api/login$", # 登录页面
|
||||
r"^/api/info$", # 获取系统信息配置
|
||||
r"^/api/info/.*$", # 系统信息配置相关接口
|
||||
]
|
||||
|
||||
# 获取数据库会话
|
||||
|
||||
26
src/static/info.template.yaml
Normal file
26
src/static/info.template.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
# 单位信息配置文件
|
||||
# 用于配置网站的基本信息、品牌信息等
|
||||
# 修改后需要重启服务生效
|
||||
|
||||
# 组织信息
|
||||
organization:
|
||||
name: "江南语析" # 完整组织名称
|
||||
short_name: "语析" # 简短名称
|
||||
logo: "/favicon.svg" # Logo文件路径
|
||||
avatar: "/avatar.jpg" # 头像文件路径
|
||||
|
||||
# 品牌信息
|
||||
branding:
|
||||
title: "Yuxi-Know" # 系统标题
|
||||
subtitle: "大模型驱动的知识库管理工具" # 副标题
|
||||
description: "结合知识库与知识图谱,提供更准确、更全面的回答" # 描述信息
|
||||
|
||||
# 功能特性
|
||||
features:
|
||||
- "📚 灵活知识库"
|
||||
- "🕸️ 知识图谱集成"
|
||||
- "🤖 多模型支持"
|
||||
|
||||
# 页脚信息
|
||||
footer:
|
||||
copyright: "© 江南语析 2025 [WIP] v0.12.138"
|
||||
1
web/public/jnu.svg
Normal file
1
web/public/jnu.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 30 KiB |
@ -46,6 +46,21 @@ export const configApi = {
|
||||
getConfig: () => apiGet('/api/config'),
|
||||
}
|
||||
|
||||
// 系统信息配置API
|
||||
export const infoApi = {
|
||||
/**
|
||||
* 获取系统信息配置
|
||||
* @returns {Promise} - 系统信息配置
|
||||
*/
|
||||
getInfoConfig: () => apiGet('/api/info'),
|
||||
|
||||
/**
|
||||
* 重新加载信息配置
|
||||
* @returns {Promise} - 重新加载结果
|
||||
*/
|
||||
reloadInfoConfig: () => apiGet('/api/info/reload')
|
||||
}
|
||||
|
||||
// 健康检查API
|
||||
export const healthApi = {
|
||||
/**
|
||||
|
||||
@ -10,11 +10,13 @@ import { Bot, Waypoints, LibraryBig, MessageSquareMore, Settings } from 'lucide-
|
||||
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { useDatabaseStore } from '@/stores/database'
|
||||
import { useInfoStore } from '@/stores/info'
|
||||
import DebugComponent from '@/components/DebugComponent.vue'
|
||||
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
||||
|
||||
const configStore = useConfigStore()
|
||||
const databaseStore = useDatabaseStore()
|
||||
const infoStore = useInfoStore()
|
||||
|
||||
const layoutSettings = reactive({
|
||||
showDebug: false,
|
||||
@ -51,7 +53,10 @@ const fetchGithubStars = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
// 加载信息配置
|
||||
await infoStore.loadInfoConfig()
|
||||
// 加载其他配置
|
||||
getRemoteConfig()
|
||||
getRemoteDatabase()
|
||||
fetchGithubStars() // Fetch GitHub stars on mount
|
||||
@ -115,8 +120,8 @@ const mainList = [{
|
||||
<div class="header" :class="{ 'top-bar': layoutSettings.useTopBar }">
|
||||
<div class="logo circle">
|
||||
<router-link to="/">
|
||||
<img src="/avatar.jpg">
|
||||
<span class="logo-text">语析</span>
|
||||
<img :src="infoStore.organization.avatar">
|
||||
<span class="logo-text">{{ infoStore.organization.short_name }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="nav">
|
||||
|
||||
@ -9,9 +9,17 @@ import 'ant-design-vue/dist/reset.css';
|
||||
import './assets/main.css'
|
||||
|
||||
const app = createApp(App)
|
||||
const pinia = createPinia()
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(pinia)
|
||||
app.use(router)
|
||||
app.use(Antd)
|
||||
|
||||
// 预加载信息配置
|
||||
import { useInfoStore } from '@/stores/info'
|
||||
const infoStore = useInfoStore()
|
||||
infoStore.loadInfoConfig().then(() => {
|
||||
console.log('应用信息配置预加载完成')
|
||||
})
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
108
web/src/stores/info.js
Normal file
108
web/src/stores/info.js
Normal file
@ -0,0 +1,108 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { infoApi } from '@/apis/public_api'
|
||||
|
||||
export const useInfoStore = defineStore('info', () => {
|
||||
// 状态
|
||||
const infoConfig = ref({})
|
||||
const isLoading = ref(false)
|
||||
const isLoaded = ref(false)
|
||||
|
||||
// 计算属性 - 组织信息
|
||||
const organization = computed(() => infoConfig.value.organization || {
|
||||
name: "江南语析",
|
||||
short_name: "语析",
|
||||
logo: "/favicon.svg",
|
||||
avatar: "/avatar.jpg"
|
||||
})
|
||||
|
||||
// 计算属性 - 品牌信息
|
||||
const branding = computed(() => infoConfig.value.branding || {
|
||||
title: "Yuxi-Know",
|
||||
subtitle: "大模型驱动的知识库管理工具",
|
||||
description: "结合知识库与知识图谱,提供更准确、更全面的回答"
|
||||
})
|
||||
|
||||
// 计算属性 - 功能特性
|
||||
const features = computed(() => infoConfig.value.features || [
|
||||
"📚 灵活知识库",
|
||||
"🕸️ 知识图谱集成",
|
||||
"🤖 多模型支持"
|
||||
])
|
||||
|
||||
// 计算属性 - 页脚信息
|
||||
const footer = computed(() => infoConfig.value.footer || {
|
||||
copyright: "© 江南大学 2025 [WIP] v0.12.138"
|
||||
})
|
||||
|
||||
// 动作方法
|
||||
function setInfoConfig(newConfig) {
|
||||
infoConfig.value = newConfig
|
||||
isLoaded.value = true
|
||||
}
|
||||
|
||||
async function loadInfoConfig(force = false) {
|
||||
// 如果已经加载过且不强制刷新,则不重新加载
|
||||
if (isLoaded.value && !force) {
|
||||
return infoConfig.value
|
||||
}
|
||||
|
||||
try {
|
||||
isLoading.value = true
|
||||
const response = await infoApi.getInfoConfig()
|
||||
|
||||
if (response.success && response.data) {
|
||||
setInfoConfig(response.data)
|
||||
console.log('信息配置加载成功:', response.data)
|
||||
return response.data
|
||||
} else {
|
||||
console.warn('信息配置加载失败,使用默认配置')
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载信息配置时发生错误:', error)
|
||||
return null
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function reloadInfoConfig() {
|
||||
try {
|
||||
isLoading.value = true
|
||||
const response = await infoApi.reloadInfoConfig()
|
||||
|
||||
if (response.success && response.data) {
|
||||
setInfoConfig(response.data)
|
||||
console.log('信息配置重新加载成功:', response.data)
|
||||
return response.data
|
||||
} else {
|
||||
console.warn('信息配置重新加载失败')
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('重新加载信息配置时发生错误:', error)
|
||||
return null
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
infoConfig,
|
||||
isLoading,
|
||||
isLoaded,
|
||||
|
||||
// 计算属性
|
||||
organization,
|
||||
branding,
|
||||
features,
|
||||
footer,
|
||||
|
||||
// 方法
|
||||
setInfoConfig,
|
||||
loadInfoConfig,
|
||||
reloadInfoConfig
|
||||
}
|
||||
})
|
||||
@ -3,8 +3,8 @@
|
||||
<div class="hero-section">
|
||||
<div class="glass-header">
|
||||
<div class="logo">
|
||||
<img src="/favicon.svg" alt="江南语析" class="logo-img" />
|
||||
<span style="font-size: 1.3rem; font-weight: bold;">江南语析</span>
|
||||
<img :src="infoStore.organization.logo" :alt="infoStore.organization.name" class="logo-img" />
|
||||
<span style="font-size: 1.3rem; font-weight: bold;">{{ infoStore.organization.name }}</span>
|
||||
</div>
|
||||
<div class="github-link">
|
||||
<a href="https://github.com/xerrors/Yuxi-Know" target="_blank">
|
||||
@ -17,13 +17,11 @@
|
||||
</div>
|
||||
|
||||
<div class="hero-content">
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<h1 class="title">{{ infoStore.branding.title }}</h1>
|
||||
<div class="description">
|
||||
<p class="subtitle">大模型驱动的知识库管理工具</p>
|
||||
<p class="subtitle">{{ infoStore.branding.subtitle }}</p>
|
||||
<p class="features">
|
||||
<span>📚 灵活知识库</span>
|
||||
<span>🕸️ 知识图谱集成</span>
|
||||
<span>🤖 多模型支持</span>
|
||||
<span v-for="feature in infoStore.features" :key="feature">{{ feature }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<button class="start-button" @click="goToChat">开始对话</button>
|
||||
@ -36,14 +34,14 @@
|
||||
<div class="preview-overlay">
|
||||
<div class="overlay-content">
|
||||
<h3>强大的问答能力</h3>
|
||||
<p>结合知识库与知识图谱,提供更准确、更全面的回答</p>
|
||||
<p>{{ infoStore.branding.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 江南语析 2025 [WIP] v0.12.138</p>
|
||||
<p>{{ infoStore.footer.copyright }}</p>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
@ -52,11 +50,12 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useInfoStore } from '@/stores/info'
|
||||
import { chatApi } from '@/apis/auth_api'
|
||||
|
||||
const title = ref('Yuxi-Know')
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const infoStore = useInfoStore()
|
||||
const githubStars = ref(0)
|
||||
const isLoadingStars = ref(false)
|
||||
|
||||
@ -113,7 +112,10 @@ const fetchGithubStars = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
// 加载信息配置
|
||||
await infoStore.loadInfoConfig()
|
||||
// 获取GitHub stars
|
||||
fetchGithubStars()
|
||||
})
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user